https://reactjs.org/ を見て、気になった書き方・機能をまとめていきます。
Inline If with Logical && Operator
特定の条件の場合のみ表示する、というシチュエーションはよくあります。
例えば、エラーが存在する場合のみ、エラーメッセージを表示するなど。
普通に書くと、下記のようになる。
class App extends Component {
render() {
let errorMessage = "XXX is required."; // or null
let errorMessageTag = null;
if (errorMessage) {
errorMessageTag = <p className="App-intro">error:{errorMessage}</p>
}
return (
<div>
{errorMessageTag}
</div>
);
}
}
https://reactjs.org/docs/conditional-rendering.html#inline-if-with-logical--operator を見ると、下記のように書けるようです。
class App extends Component {
render() {
let errorMessage = "XXX is required."; // or null
return (
<div>
{errorMessage &&
<p className="App-intro">error:{errorMessage}</p>
}
</div>
);
}
}
Preventing Component from Rendering
ただ、上記のような場合は、別コンポーネントにしたほうが良さそうです。
https://reactjs.org/docs/conditional-rendering.html#preventing-component-from-rendering
function ErrorMessage(props) {
if (!props.errorMessage) {
return null;
}
return (
<div>error:{props.errorMessage}</div>
);
}
class App extends Component {
render() {
let errorMessage = "XXX is required."; // or null
return (
<div>
<ErrorMessage errorMessage={errorMessage} />
</div>
);
}
}
(ErrorMessage
はタグ名になるのでUpperCamelCaseになりますが、functionでもあるのでちょっと気持ち悪い。)
Inline If-Else with Conditional Operator
特定の条件によってAとBの表示を切り替える、というシチュエーションもよくあります。
例えば、「ログインボタン」と「ログアウトボタン」を切り替えたり。
そのまま書くと、下記のようになる。
class App extends Component {
render() {
let flag = true;
let sample = null;
if (flag) {
sample = <p className="App-intro">Hoge.</p>;
} else {
sample = <p className="App-intro">Fuga.</p>;
}
return (
<div>
{sample}
</div>
);
}
}
https://reactjs.org/docs/conditional-rendering.html#inline-if-else-with-conditional-operator を見ると、もっと手軽に書けそうです。
class App extends Component {
render() {
let flag = false;
return (
<div>
{flag ? (
<p className="App-intro">Hoge.</p>
) : (
<p className="App-intro">Fuga.</p>
)}
</div>
);
}
}
Specialization
Dialogなどは、外枠が共通で、中身が「タイトルだけ」だったり「メッセージに装飾がついてる」だったり「ボタンが複数」だったりします。
そんなときは、 children
という特別なpropを使うようです。
function Dialog(props) {
const style = {
backgroundColor: "#ff0000",
margin: "10px"
};
return <div style={style}>{props.children}</div>;
}
class App extends Component {
render() {
return (
<div>
<Dialog>メッセージのみ</Dialog>
<Dialog>
<span>ボタンもあるイメージ</span>
<button href="alert('test');">OK</button>
</Dialog>
</div>
);
}
}
Using Dot Notation for JSX Type
https://reactjs.org/docs/jsx-in-depth.html#using-dot-notation-for-jsx-type
このリンクにあるように、<MyComponents.DatePicker />
みたいにモジュール化?できます。
プロジェクト内の汎用のコンポーネントを MyComponents
の中に入れておき、そこから画面ごとのコンポーネントを作成する、とかもいいかもしれません。
Choosing the Type at Runtime
https://reactjs.org/docs/jsx-in-depth.html#choosing-the-type-at-runtime
動的に表示するタグを決めることも出来ます。
便利そうですが、使い所は思いついていないです。
const Sample1 = () => <div>This is Sample1.</div>;
const Sample2 = () => <div>This is Sample2.</div>;
class App extends Component {
render() {
let flag = true; // or false
const Hoge = flag ? Sample1 : Sample2;
return (
<div>
<Hoge />
</div>
);
}
}
Spread Attributes
...
を使うと、objectを展開してパラメータにすることができるようです。
例えば、次の2つは同じ結果になります。
function App1() {
return <Greeting firstName="Ben" lastName="Hector" />;
}
function App2() {
const props = {firstName: 'Ben', lastName: 'Hector'};
return <Greeting {...props} />;
}
それ以外にも、一部(この場合はkind)を消化して、それ以外を子要素に渡すといったこともできそうです。
const Button = props => {
const { kind, ...other } = props;
const className = kind === "primary" ? "PrimaryButton" : "SecondaryButton";
return <button className={className} {...other} />;
};
const App = () => {
return (
<div>
<Button kind="primary" onClick={() => console.log("clicked!")}>
Hello World!
</Button>
</div>
);
};
ただ、安易にこれを使いすぎると、どのパラメータが必要・有効なのかが分からなくなってしまいそうです。
(そのために、FlowやTypeScriptで型定義をしておいたほうがいいかも?)
Children in JSX - String Literals
HTMLとしてのみやすさを重視すると、タグ直後や途中で改行を入れたくなります。
ただ、通常のHTMLでは改行・スペースが反映されてしまい、レイアウトが崩れる場合がありました。
JSXでは、改行やスペースを削除してくれるようです。
そのため、下記は同一のHTMLとしてレンダリングされます。
class App extends Component {
render() {
return (
<div>
<div>Hello World</div>
<div>
Hello World
</div>
</div>
);
}
}
Refs and the DOM
フォーカスや文字の選択などの、DOMの直接操作が必要な事態は出てきます。
そのために、idを振って、document.getElementById('foo')
としてDOMを取得することは出来ます。
Reactでは、同様のことをref
を使って実現できます。
class App extends Component {
constructor(props) {
super(props);
this.focusTextInput = this.focusTextInput.bind(this);
}
focusTextInput() {
this.textInput.focus();
}
render() {
return (
<div>
<input
type="text"
ref={input => {
this.textInput = input;
}}
/>
<input
type="button"
value="Focus the text input"
onClick={this.focusTextInput}
/>
</div>
);
}
}
Fragments
Reactのcomponentは、特定のタグの下に置く必要があります。
なので、下記のような書き方は出来ません。
const Sample0 = () => (
This is <span style={{ color: "#f00" }}>Sample1</span>.
);
ただ、<div>
タグが必要ない場合もあります。<React.Fragment>
を使えば、実現できるようです。
const Sample1 = () => (
<React.Fragment>
This is <span style={{ color: "#f00" }}>Sample1</span>.
</React.Fragment>
);
const Sample2 = () => (
<div>
This is <span style={{ color: "#f00" }}>Sample2</span>.
</div>
);
class App extends Component {
render() {
return (
<div>
<Sample1 />
<Sample2 />
</div>
);
}
}
レンダリング結果は下記のようになります。
<div>
This is <span style="color: rgb(255, 0, 0);">Sample1</span>.
<div>This is <span style="color: rgb(255, 0, 0);">Sample2</span>.</div>
</div>
まとめ
こんな感じで、いろいろな書き方があるので、それらを駆使して読みやすいコードを心がけていきたいですね。