関数コンポーネント内の関数はどこに置くべきでしょうか? 質問する

関数コンポーネント内の関数はどこに置くべきでしょうか? 質問する

<canvas>見つけたクールなアニメーションを変換しようとしていますここを React の再利用可能なコンポーネントに変換します。このコンポーネントには、キャンバス用の親コンポーネントが 1 つと、 用の子コンポーネントが多数必要になるようですfunction Ball()

Ballsパフォーマンス上の理由から、 は多数存在するため、 をステートレス コンポーネントにする方がよいでしょう。私はステートレス コンポーネントの作成にあまり詳しくなく、 で定義されているthis.update()およびthis.draw関数をどこで定義すればよいのか疑問に思いましたfunction Ball()

ステートレス コンポーネントの関数はコンポーネントの内側に配置されますか、それとも外側に配置されますか? つまり、次のどちらが優れていますか?

1:

const Ball = (props) => {
    const update = () => {
        ...
    }

    const draw = () => {
        ...
    }

    return (
       ...
    );
}

2:

function update() {
     ...
}

function draw() {
     ...
}

const Ball = (props) => {
    return (
       ...
    );
}

それぞれの長所と短所は何ですか? また、私のような特定のユースケースでは、どちらかがより適しているでしょうか?

ベストアンサー1

最初に注意すべきことは、ステートレスな機能コンポーネントにはメソッドを持たせることができないということです。つまり、ステートレスな機能コンポーネントの場合は、呼び出しupdatedrawレンダリングを期待すべきではありません。Ball

ほとんどの場合、関数はコンポーネント関数の外側で宣言する必要があります。そうすることで、関数は一度だけ宣言され、常に同じ参照が再利用されます。関数を内側で宣言すると、コンポーネントがレンダリングされるたびに関数が再度定義されます。

たとえば、コンポーネントのプロパティに基づいて異なる動作をするイベント ハンドラーとして割り当てるなど、コンポーネント内で関数を定義する必要がある場合があります。ただし、関数を外部で定義してBallプロパティにバインドすると、コードがはるかにわかりやすくなり、関数updatedraw関数が再利用できるようになります。

// you can use update somewhere else
const update = (propX, a, b) => { ... };
    
const Ball = props => (
  <Something onClick={update.bind(null, props.x)} />
);

使用している場合フックを使用すると、useCallback関数の依存関係のいずれかが変更された場合にのみ関数が再定義されるようにすることができます (props.xこの場合は次のようになります)。

const Ball = props => {
  const onClick = useCallback((a, b) => {
    // do something with a, b and props.x
  }, [props.x]);

  return (
    <Something onClick={onClick} />
  );
}

これは間違ったやり方:

const Ball = props => {
  function update(a, b) {
    // props.x is visible here
  }
    
  return (
    <Something onClick={update} />
  );
}

を使用する場合useCallbackupdate関数をuseCallbackフック自体に定義するか、コンポーネントの外部に定義するかは、何よりも設計上の決定になります。 およびupdate/またはコンポーネントのクロージャのスコープにアクセスして、たとえば状態を読み書きするかどうかを考慮する必要があります。個人的には、最初から過剰なエンジニアリングを防ぐために、デフォルトでコンポーネント内に定義し、必要な場合にのみ再利用できるようにすることを選択しています。その上、アプリケーション ロジックの再利用は、より具体的なフックを使用して、コンポーネントを表示目的に残す方が適切です。フックを使用しながらコンポーネントの外部で関数を定義するかどうかは、アプリケーション ロジックに必要な React からの分離の度合いによって決まります。

別の共通の議論問題はuseCallback、すべての関数で常にそれを使用するかどうかです。つまり、オプトインまたは常にお勧め常に を使用することをお勧めしますuseCallback。関数を でラップしないことで多くのバグが発生しましたがuseCallback、ラップすることでパフォーマンスやロジックに何らかの影響が出るシナリオは 1 つもありませんでした。ほとんどの場合、依存関係が変わらない限り参照を保持したいので、関数自体を他のエフェクト、メモ、コールバックの依存関係として使用できます。多くの場合、コールバックは他の要素にプロパティとして渡され、 でメモ化した場合、コストがどれだけuseCallback安いか高いかに関係なく、他のコンポーネントのプロパティは変更されません (したがって、再レンダリングされます)。コンポーネントで宣言された関数が何千個も見られましたが、 を使用することでマイナス面が生じたケースは 1 つもuseCallbackありませんでした。一方、 でメモ化されていない関数のほとんどは、useCallback最終的には でメモ化するように変更され、開発者が でメモ化しないことの影響を認識していない場合は深刻なバグやパフォーマンスの問題が発生します。技術的にはを使用すると、追加の関数を作成するためパフォーマンスが低下しますuseCallbackが、使用するかuseCallbackどうかに関係なく常に発生する関数の再宣言や、React と JavaScript の全体的なフットプリントと比較すると、無視できるほど小さいものです。したがって、 と使用しない場合のパフォーマンスへの影響について本当に心配している場合はuseCallback、React が適切なツールであるかどうかを自問する必要があります。

おすすめ記事