しばらくReactを使用している場合は、おそらく遭遇したでしょう コンテナ & プレゼンテーションコンポーネント 、またはスマートでダムなコンポーネント。 これらの用語は、 パターン これは、ReactコンポーネントのUIレイヤーをロジックから分割します。
UIをビジネスロジックから分離することは、Reactに固有のものではありません。関心の分離は、次のような設計原則です。 すでに70年代に出回っています。 たとえば、データベースにアクセスするコードをバックエンドのビジネスロジックから分離するのが一般的な方法です。
そのため、Reactでは、すべてのロジックを含むコンテナーコンポーネントを作成することでこの問題を解決しました。このコンテナーは、プロップを介してデータをプレゼンテーションコンポーネントに渡します。
Reactフックの導入により、これに対する新しいアプローチがあります。 カスタムフック.
なぜロジックをコンポーネントから分離する必要があるのですか?
ロジックをReactコンポーネントから切り離す前に、その理由を知っておく必要があります。
すべての関数またはコンポーネントがXNUMXつのことだけを担当するようにコードを編成すると、多くの利点があります。 変更と保守が簡単 (デイブとアンドリューはこれを「直交性彼らの本の中で」 実用的なプログラマー).
これをReactに適用すると、コンポーネントがよりクリーンで整理されたように見えます。 たとえば、UIを編集する前に、ロジックの壁を越えてスクロールする必要はありません。
このようにコードを整理すると、見栄えが良くなり、ナビゲートしやすくなるだけでなく、フックを変更してもUIに影響がないため、変更も簡単になります。その逆も同様です。
テストもよりアクセスしやすくなります。必要に応じて、UIとは別にロジックをテストできます。 しかし、私にとって最も重要な利点は、このアプローチが私のコードをどのように編成するかです。
Reactフックでロジックを切り離す方法
ロジックをコンポーネントから切り離すために、最初にカスタムフックを作成します。
このコンポーネントを例として取り上げましょう。 基数と指数の指数値を計算します。
あなたは完全なソースコードを見つけることができます こちら.
コードは次のようになります。
export const ExponentCalculator = () => {
const [base, setBase] = useState(4);
const [exponent, setExponent] = useState(4);
const result = (base ** exponent).toFixed(2);
const handleBaseChange = (e) => {
e.preventDefault();
setBase(e.target.value);
};
const handleExponentChange = (e) => {
e.preventDefault();
setExponent(e.target.value);
};
return (
<div className="blue-wrapper">
<input
type="number"
className="base"
onChange={handleBaseChange}
placeholder="Base"
value={base}
/>
<input
type="number"
className="exponent"
onChange={handleExponentChange}
placeholder="Exp."
value={exponent}
/>
<h1 className="result">{result}</h1>
</div>
);
};
これはすでに問題ないように見えるかもしれませんが、このチュートリアルのために、 絵 ここにはもっとロジックがあります。
最初のステップとして、 ロジックをカスタムフックに移動します コンポーネント内で呼び出します。
const useExponentCalculator = () => {
const [base, setBase] = useState(4);
const [exponent, setExponent] = useState(4);
const result = (base ** exponent).toFixed(2);
const handleBaseChange = (e) => {
e.preventDefault();
setBase(e.target.value);
};
const handleExponentChange = (e) => {
e.preventDefault();
setExponent(e.target.value);
};
return {
base,
exponent,
result,
handleBaseChange,
handleExponentChange,
};
};
export const ExponentCalculator = () => {
const {
base,
exponent,
result,
handleExponentChange,
handleBaseChange,
} = useExponentCalculator();
// ...
};
このフックをに移動できます 別のファイル より顕著な関心の分離のために。
さらに、フックをより小さく、再利用可能な関数にさらに分離することができます。 この場合、抽出できるのは calculateExponent
.
useExponentCalculator.js
const calculateExponent = (base, exponent) => base ** exponent;
const useExponentCalculator = () => {
const [base, setBase] = useState(4);
const [exponent, setExponent] = useState(4);
const result = calculateExponent(base, exponent).toFixed(2);
// ...
};
これらの関数のテストは、最初の例のコンポーネント全体のコードをテストするよりもはるかに簡単です。 Reactコンポーネントをサポートする必要さえないNode.jsテストライブラリでそれらをテストすることができます。
これで、コンポーネントとフックのコードにフレームワーク固有のコード(React)が含まれますが、ビジネスロジックは、後で定義するさまざまな関数(フレームワークに依存しない)に存在します。
ベストプラクティス
命名
コンポーネントにちなんでカスタムフックに名前を付けます。 use
およびコンポーネントの名前(例: useExponentCalculator
)。 それから私は 同じファイル フックとして。
別の命名規則に従うこともできますが、私はお勧めします 一貫性を保つ あなたのプロジェクトで。
カスタムフックの一部を再利用できる場合は、通常、下の別のファイルに移動します src/hooks
.
無理しないで
実用的になるようにしてください。 コンポーネントにJSが数行しかない場合は、ロジックを分離する必要はありません。
JS 内の CSS
CSS-in-JSライブラリを使用している場合(useStyles
)、このコードを別のファイルに移動することもできます。
フックと同じファイルに移動できます。 ただし、同じファイル内のコンポーネントの上に保持するか、大きくなりすぎた場合は独自のファイルに移動することをお勧めします。
まとめ
カスタムフックを使用するとコードが改善されると思うかどうかにかかわらず、最終的には個人的な好みになります。 コードベースに多くのロジックが含まれていない場合、このパターンの利点はあまり関係ありません。
カスタムフックは、モジュール性を高めるためのXNUMXつの方法にすぎません。 私も強くお勧めします コンポーネントと機能をより小さく、再利用可能なチャンクに分割する 可能であれば。
このトピックは、より一般的なレベルでも説明されています。 実用的なプログラマー。 私はこの本の私の好きなトピックをカバーする記事を書いたので、それがあなたに興味があるなら、必ず それをチェックしてください.