React.jsでの開発を始めてから微妙にハマったポイント、また「これを早めに知っておけばもっとコードを簡潔に書けたのに・・!」という点がいくつかあったので、それらのTipsを共有します。
#renderで返すComponentは単一の親でなければならない
まずは入門編。Reactを始めた人は一度はエラーになったことがあるかも。
renderメソッドで返すのは単一の親のComponentであり、複数の親のComponentを返すことは出来ません。
必ず一つの親になるようにWrapしてあげましょう。
// エラーになる
render(){
return(
<div>aaa</div>
<div>bbb</div>
);
}
// 正常
render(){
return(
<div>
<div>aaa</div>
<div>bbb</div>
</div>
);
}
#renderで空を返す
子コンポーネントで親から渡されたデータによって空のComponentを返したい場合があります。
そんな時は空のHTML要素を使わなくてもnullかfalseで返せます。
(ただしundefinedは使えません)
render() {
if (!this.props.isShow) {
return null; // もしくはreturn false;
}
return (
<div>
表示します
</div>
);
}
#JSX内でif/else文の判定やループを行う
条件分岐による要素の変更やループでの要素作成を行う場合、まず変数に代入しておいて、最後のreturn時にJSX内で変数を割り当てる方法があります。
render() {
const label = this.props.isShow ? <div>テスト</div> : null;
const commentNodes = this.props.data.map((comment) => {
return (
<Comment author={comment.author}>
{comment.text}
</Comment>
);
});
return (
<div>
{label}
<div className="commentList">
{commentNodes}
</div>
</div>
);
}
または規模がある程度大きい場合子コンポーネントに分割するのを検討します。
しかしごく単純な処理はJSX内でインラインで直接条件分岐やループを書きたい場合もあります。
そこでJSXのインラインで処理する記法が以下になります。
render() {
return (
<div className="commentList">
{(() => {
if (this.props.isShow) {
return <div>テスト</div>;
}
})()}
{(() => {
return (
this.props.data.map((comment)=> {
return <Comment author={comment.author}>
{comment.text}
</Comment>
})
);
})()}
</div>
);
}
アロー関数を用いた即時関数で処理する方法ですね。
これはReact公式のドキュメントにも記載してあります。
https://facebook.github.io/react/tips/if-else-in-JSX.html
ただこの記事に対するコメントでも指摘があったのですが、即時関数を使う必要は無く、もっと簡潔に書けます。
というわけで↑のコードをLet's修正。
render() {
return (
<div className="commentList">
{this.props.isShow && <div>テスト</div>}
{this.props.data.map((comment)=> {
return (
<Comment author={comment.author}>
{comment.text}
</Comment>
);
})}
</div>
);
}
うん、見通しが良くなった笑
{this.props.isShow && <div>テスト</div>}
の部分は三項演算子でも構いません。
{this.props.isShow ? <div>テスト</div> : null}
ただ全てにおいてインラインで書けば良いというわけではなく、ケースによってコンポーネントの分割やrenderの切り出しを使い分けましょう。
(指摘して頂いた皆さんありがとうございます )
#onKeyDown/onKeyPress/onKeyUpイベントでのキーコード取得の違い
実はこの3つのイベントの中でonKeyPressだけキーコード取得の方法が違います。
onKeyDown/onKeyUpは引数のイベントのkeyCodeプロパティから取得できますが、onKeyPressでkeyCodeプロパティから取得しようとしても常に0が返ってきます。
onKeyPressでの正しいキーコードの取得はkeyCodeプロパティではなくcharCodeになります。
onKeyPress(e) {
console.log(`onKeyPress KeyCode:${e.charCode}`)
}
onKeyDown(e) {
console.log(`onKeyDown KeyCode:${e.keyCode}`)
}
onKeyUp(e) {
console.log(`onKeyUp KeyCode:${e.keyCode}`)
}
render() {
return (
<div>
<form onSubmit={this.onSubmit}>
<input type="text" onKeyDown={this.onKeyDown} onKeyPress={this.onKeyPress} onKeyUp={this.onKeyUp}/>
<button type="submit">登録</button>
</form>
</div>
);
}
#classNameに文字列と変数を組み合わせて割り当てる
状態によってclass名を割り当てデザインを変更したい場合は往々にあります。
例えば固定のclass名であればダブルクオーテーションでくくります。
<div className="header">
次に変数を割り当てたい場合は{}でくくります。
<div className={showClass}>
それでは固定のclass名と変数の組み合わせたい時はどうでしょうか?
間違いがちなのが下の書き方ですね。
<div className="header {showClass}">
これはエラーになります
記法として二つあります。
まずこれも一つの変数に代入してから割り当てる方法
const headerClass = "header " + (isShow ? "show" : "hide");
...
<div className={headerClass}>
二つ目はES6のテンプレートリテラルを使用してインラインで書きます。
<div className={`header ${isShow ? "show" : "hide"}`}>
僕は二つ目の方法をよく使います。
(個人的にテンプレートリテラルはES6で最も便利な文法の一つだと思ってます )
他に思いついたTipsがあったら追記していきますので宜しくお願いします。