JavaScript

React Hooksによるパフォーマンスチューニングを考える

「Reactで作ったアプリがなんだかモッサリしている」
「SPAなのに動きがカクカク」
「快適な動作にしたいけど、どこに問題があるのか分からない」

こうした悩みを抱えるReact開発者の方のための記事です。

ということでこんにちは、株式会社PlaygroundのWebエンジニア、稲垣です。

ユーザーに素晴らしい体験を与えて、アプリからの離脱率を下げるために、フロントエンドのパフォーマンスはとても重要視されています。

この記事では、React v16.8.0以降で使えるHooksを使ったパフォーマンスチューニングについて解説します。

この記事で解説すること
  • Reactのレンダリングの仕組み
  • useMemoを用いたパフォーマンスチューニング
  • useCallbackを用いたパフォーマンスチューニング

Reactのパフォーマンスチューニングをする前に…レンダリングの仕組みを理解しよう

いきなり解説を放棄するようですが、Reactのパフォーマンスについてはこちらの記事がかなり詳しいです。笑

この記事のポイントをまとめると以下の通りです。

ここにタイトルを入力
  • 不要な再レンダリングを減らそう
  • 親コンポーネントのrenderに連鎖する子コンポーネントのrenderを意識しよう
  • Class ComponentならshouldComponentUpdate()メソッドを使おう
  • Reduxでレンダリングするコンポーネントを限定的にしよう
  • なるべくFunctional Componentを使おう
  • Code SplittingやDynamic importを使おう
  • サーバーサイドレンダリングや静的ジェネレーターを使おう

いくつかは他のライブラリや、フレームワークなどを使わないと実現できないですね。

ここからはReact(Hooks)だけで実装できるパフォーマンスチューニングを紹介します。

React HooksのuseMemoを使ったパフォーマンスチューニング

メモ化された値を返します。

“作成用” 関数とそれが依存する値の配列を渡してください。useMemo は依存配列の要素のいずれかが変化した場合にのみメモ化された値を再計算します。この最適化によりレンダー毎に高価な計算が実行されるのを避けることができます。

フック API リファレンス – React

公式からの引用ですが、正直わかりにくい表現ですよね。笑

英語ドキュメントの和訳なので、日本語的にもちょっと難解だと思います。

これを噛み砕いて解説しますね。

まず“作成用”関数はuseMemo()に渡す関数です。

そして“作成用”関数内で使われている値を、依存する値と呼んでいますね。

コード例を示すと以下の通りです。

// useMemoを使わない例
const getArticleIds = () => articles.map(article => article.id)

// useMemoを使った例 --> articlesに変更があった時のみ再実行する
const getArticleIds = useMemo(() => articles.map(article => article.id), [articles])

 

この例では記事IDを取得する関数getArticleIds()に、useMemoを使っています。

useStateで作成したarticlesという値があったとして、そのarticlesが変更(更新)された時のみ、getArticleIds()は再実行されます。

  • 作成用関数:() => articles.map(article => article.id)
  • 依存する値:articles

useMemoの役割を一言で表すと、「関数の実行結果を保存して、依存する値に変更があった時に再実行する」です。

React HooksのuseCallbackを使ったパフォーマンスチューニング

メモ化されたコールバックを返します。

インラインのコールバックとそれが依存している値の配列を渡してください。useCallback はそのコールバックをメモ化したものを返し、その関数は依存配列の要素のいずれかが変化した場合にのみ変化します。これは、不必要なレンダーを避けるために(例えば shouldComponentUpdate などを使って)参照の同一性を見るよう最適化されたコンポーネントにコールバックを渡す場合に便利です。

フック API リファレンス – React

useCallbackの説明も、まーイマイチわかりにくい。

useCallbackとuseMemoの違いは、useMemoが関数の実行結果を返すのに対して、useCallbackはコールバック関数自体を返すという点です。

子コンポーネントのpropsに関数を渡す場合、Class Componentでメソッドをbind()していた代わりに、useCallbackで作った関数を渡すと、無駄なレンダリングを減らすことができます。

ABOUT ME
稲垣 貴映
サーバーエンジニア兼Webフロントエンジニア。 新卒で独立系SIerに入社後、金融系システム基盤の構築・運用を3年間経験。 プログラミングを独学していた頃に、CEOの馬谷が開講していたSwiftスクールに通い、2019年9月に入社。 趣味はブラジル音楽の演奏。

COMMENT

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA