O hirunewani blog

Q. コンポーネントをuseCallbackで作るかスコープ外の関数として切り出すべきか

Created at

個人的には出来る限りスコープ外の関数としてコンポーネントを切り出すべきだと考えている。パフォーマンス、コードとしての質、将来性の観点から説明を行った

Githubの通知を眺めていると、useCallbackを利用してコンポーネントを作っている次のようなコードに対して、コンポーネントとして切り出した方がいいのではないか?とレビューコメントが付いているのを見つけた。

const LargeComponent = () => {
  // many hooks

  const ConditionalComponent = () => {
    // ...
    if (value === null) {
      return null;
    }
    return <HogeComponent value={value} />;
  };

  return (
    <div>
      <ConditionalComponent />
      <button onClick={handleClick}>Click me</button>
    </div>
  );
};

このコメントを補足する形で、次のような内容のコメントを付けた。

パフォーマンスについて

多くのケースで、ほぼ差は発生しない。

useCallbackは、その仕組み上、比較やキャッシュの参照のオーバヘッドが存在するが、それによってuseCallbackを利用しない方が良いと言えるような差は基本的に発生しない。

コードの質について

次のような主張があって然るべきだと思う。

  • 関数やコンポーネントはなるべく純粋であるべき
  • 利用されない可能性があるものは分離すべき
    • 複雑度を下げるように圧力がかかるべき

実際このようにコンポーネント内のコンポーネントが全体的に許容されていくと、ここのコンポーネントに対して網羅的なテストを書くことが難しくなっていく。

また、Reactコンポーネントとしての一貫性を損なうという主張も考えられる。useCallback内などで他のhooksが呼ばれることは、本来想定されておらずバグの原因になりうるため、避けるべきだ。

将来性について

以前からReactチームなどは、実際にパフォーマンスが問題になるようなケースを除いて、useCallbackやuseMemoを積極的には利用していないように思われる。

またReact Compilerも控えており、問題になっていない/なりそうなければ利用しなくて良いという主張には一定の合理性があるように思う。

一方で、useCallbackやuseMemoを利用するコストは低いため、積極的に利用して構わないという主張もあって然るべきだ。