Edited at

React.jsの知っておいて損はないTips

More than 1 year has passed since last update.

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の切り出しを使い分けましょう。

(指摘して頂いた皆さんありがとうございます :pray: )


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}">

これはエラーになります :no_good:

記法として二つあります。

まずこれも一つの変数に代入してから割り当てる方法

const headerClass = "header " + (isShow ? "show" : "hide"); 

...

<div className={headerClass}>

二つ目はES6のテンプレートリテラルを使用してインラインで書きます。

<div className={`header ${isShow ? "show" : "hide"}`}>

僕は二つ目の方法をよく使います。

(個人的にテンプレートリテラルはES6で最も便利な文法の一つだと思ってます :star: )

他に思いついたTipsがあったら追記していきますので宜しくお願いします。