O hirunewani blog

ReactコンポーネントはJSXとして呼ぶべき

Created at

ReactコンポーネントをJSX形式ではなく、ただの関数として呼ぶとバグの原因になる場合がある。これが原因のバグの相談を度々受けるので、問題になる例と対策をまとめた。

ReactコンポーネントをJSXとして記述しない場合、Reactエレメントとしてトランスパイルされず、Reactコンポーネント内でuseStateなどを利用しているとバグが発生する原因になる。これは今後のトランスパイルの仕方によって解消する可能性もあるかもしれないし、そもそも解消する必要がないかもしれない。

問題が発生する例

次のアプリは、ReactNodeを返すHogeコンポーネントと、それをrenderHogeという名前の変数に代入しただけの関数に、全く同じ配列の要素をそれぞれに渡して呼ぶ。Shuffleを押すと配列の中身が入れ替わり、数字が入れ替わることを期待する。

https://react-ts-ncsxsw.stackblitz.io/

この例では、renderHogeの方だと再レンダリングがされなくなる。React DevtoolのComponentsタブをよく見るとrenderHogeはコンポーネントとして表示されておらず、hooks→evalの中に入っていることが分かる。

コンポーネントとして振る舞わなくなるため、このことを認識せずに利用すると様々なバグの原因になりうる。

対策

JSXがトランスパイルされるということを意識せずにコードを書いている人はそこそこおり、次のように配列をマップするようなケースで書かれていることが多い。

const List = ({ data, renderItem }) => {
  return <ul>{data.map(renderItem)}</ul>;
};

次のように名前を変更してJSXとして呼べば回避できる。

const List = ({ data, renderItem: RenderItem }) => {
  return (
    <ul>
      {data.map(item => {
        return <RenderItem key={item.key} {...item} />;
      })}
    </ul>
  );
};