【React】 PureComponent にアロー関数を渡してはいけない
React v15.3 で追加された PureComponent は便利だけど、少し間違えるとパフォーマンス上がりませんよという話。
記事を書こうと思い立ったあとで調べたら先人がいらっしゃった。
二番煎じだが、自戒のためにもメモを残しておく。
PureComponent とは
shouldComponentUpdate
をよしなにしてくれる。 props を shallow 比較して変更があったら render する。
React のレンダリングパフォーマンスを上げようと思ったら shouldComponentUpdate
をいじるのは避けて通れないけど、PureComponent
のおかげであまり考えなくて済む。 state を持たないコンポーネントはだいたい PureComponent 使えば良い感がある。
しかし、思わぬ落とし穴がある。
PureComponent にアロー関数を渡してはいけない
本質だけを書くと、 Button
が PureComponent
だとして、次のように使うとする。
render () { return ( <Button onClick={() => this.setState({clicked: true})} text='hoge' /> ) }
このとき、この render が実行されるたびに、 onClick
に渡すアロー関数が再生成される。すると、 Button
の shouldComponentUpdate
が「propsに変更があったね」という判定をして true を返す。だから Button
内の render が毎回実行されるというわけだ。
shouldComponentUpdate: 「何者だ!」 onClick: 「新しい関数です」 shouldComponentUpdate: 「よし通れ」
こういう感じである。だからせっかく PureComponent
でパフォーマンス向上しようとしても、上のほうのコンポーネントがアロー関数を使っていたりすると、全体の state が変わるたびに末端のコンポーネントまで render が走ったりしてしまう。思わぬ落とし穴だ。
ほかのアンチパターン
上のブログ記事にせっかく載っていたので、ほかのアンチパターンも紹介する。アンチパターンである理由は上と同じなので、繰り返さない。
コードは引用する。
デフォルト値として新たに変数を宣言しちゃうやつ。
class Table extends PureComponent { render() { return ( <div> {this.props.items.map(i => <Cell data={i} options={this.props.options || []} /> )} </div> ); } }
bind を render の中でやっちゃうやつ。
class App extends PureComponent { update(e) { this.props.update(e.target.value); } render() { return <MyInput onChange={this.update.bind(this)} />; } }