🛸

【React】return の後に関数定義をする Hoisting Pattern を提唱したい

に公開

私が React でよく使うデザインパターン(?)を紹介します。
JavaScript の Hoisting (宣言の巻き上げ) を使うので Hoisting Pattern と勝手に呼んでいます。
といっても何か特別な書き方をするわけでなく、ただ return の後に function を書くだけです。

MyButton.tsx
'use client';

import { ReactNode, useEffect, useState } from 'react';

type Props = {
  children?: ReactNode;
};

export function MyButton({ children }: Props) {
  const [state, setState] = useState('');
  const [count, setCount] = useState(0);

  useEffect(() => {
    initialize();
  }, []);

  useEffect(() => {
    notifyCount();
  }, [count]);

  return (
    <>
      <button type="button" onClick={onClick}>
        {children}
      </button>
      <p>{state}</p>
      <p>{count}</p>
    </>
  );

  function initialize() {
    setState('initialized');
  }

  function notifyCount() {
    setState(`count is ${count}`);
  }

  function onClick() {
    setCount((prev) => prev + 1);
  }
}

上記のコードは Hoisting によって関数定義が巻き上げられるため正常に動作します。
また、関数内から定義した state にもアクセスできます。

メリット

この Hoisting Pattern のメリットは主に2つあります。
1つ目は return が上の方に表示されるためUI定義にたどりつきやすい点で、
2つ目は 関数定義の書き方を統一できる点です。

return が上の方に表示されるためUI定義にたどりつきやすい

個人的にですが、コンポーネントを見る時に一番最初に見たいのは return の中身です。
というのもコンポーネントを確認する際には initializenotifyCount 等といったビジネスロジックの具体的な実装には関心がないためです。
return でどのような State を使用しているのか確認してからビジネスロジックを見る流れになると思うので、Hoisting Pattern を使用するとこの一連の流れをスムーズに行うことができます。

関数定義の書き方を統一できる

Hoisting Pattern を使用する場合は名前付き関数は全て function で定義しないといけません。
というのも return の後に アロー関数 使用できないためです。
この制限によってコーディングルールを設けずとも関数定義の記述を統一することができます。

デメリット

あえてデメリットを上げるのであれば、Hoisting という仕様自体がJavaScript独自であるため、あまり一般的でないという点でしょうか。

最後に

私は2年ほど React を主戦場にしていて、その間にたどり着いた個人的ベストプラクティスの一つです。
人によっては好き嫌いあるかもしれませんが、よかったら使ってみてください。

HCプロデューステックブログ

Discussion