反応における回想とその神話
12232 ワード
おい、子供、あなたはどうですか?今日、我々は少し深く反応して、うまくいけば、あなたが持っている誤解のいくつかについてあなたの心を吹き飛ばします.特に、レンダリングと再レンダリングについて話し、どのようにコンポーネントを再レンダリングするのを防ぐか、最初の場所で行うかどうかについて話します.
我々が始める前に、用語について整列しましょうので、我々はこの記事を通して同じページにいます
これらの用語を使用して、コンポーネントがDOMに追加され、その後画面上に描画されるか、DOMと画面から削除された瞬間を記述します.それは常に高価な操作です.
一般的な信念にもかかわらず、“レンダリング”という用語は、画面上のレンダリングとは関係ありません.代わりに、
小道具と状態の間の主な、そして最も重要な違いは、小道具がレンダリングの上で更新されるということである.これは、状態がpropsに依存するたびに、ライフサイクル効果を導入する必要があることを意味します.
反応中の原始値は、JavaScriptの原始的な値です.あなたがそれらが何であるかについてわからないならば、この記事はあなたのためにあまりにハードコアであるかもしれません.非プリミティブは、残りの関数です.原始的な/非原始的なプロップと原始的な/非原始的な価値ある値を持つことができます.
親指のルールとして選択した場合は、常に原始的な小道具を非原始的な小道具にする必要があります:
まだ確信していない?では、以下の2つのコンポーネントを考え、どれがあなたの呼び出しスタックを爆破するかを推測してください(ヒント:一つだけです).
ほとんどの反応フックは、第2引数として最初の引数と依存配列としてコールバックを取るので、依存関係配列から値のどれかが変化するならば、コールバックは呼ばれます.例外なく、すべての小文字、またはコールバックで使用されるプロップから派生した値は、依存配列で表示されます.繰り返しますが、この記事は依存関係の配列についてではありませんし、なぜ説明するのも気にしません.しかし、依存関係がなぜオンラインで疲れ果ててしまうのか、良い説明を見つけることができます.私は強く
クール!いくつかの神話のいくつかの反応の開発者を信じて起動し、それらの1つなら、見てみましょう!
これはスーパー既知と同じ時間スーパーダム1です.イベントハンドラをインラインで実行しないでください.
それで、解決は簡単です
我々が決心したように、メモ化フックはほとんど無意味です(少し後で彼らについて).したがって、どうやってこの再描画問題を修正するのですか.ミート
なぜそれがより多くの演奏者が尋ねることができるです.多くの小道具が副木のノードの数と比較して平均的に少ないので、デフォルトで反応するので、非常に軽量操作である浅い比較を使用します.あなたがする必要があるのは
言い換えれば、あなたが完全にすべての非原始的な小道具を覚えることに完全にコミットする必要がありますmemoizationゲームをプレイした場合、それ以外の場合だけでなく、それは無意味になりますが、あなたのアプリは、それは両方の支柱の比較と各再レンダリングの拡散を実行するように最適化されます.
同じ原理は
それで、あなたは反応で回想を使うべきですか?それは良い質問です、そして、あなたが現在推測したかもしれないように、答えは単純でありません.しかし、あなたが決めるのを助けるかもしれない2、3の規則を要約しましょう あなたは、非原始的な状態効果を引き起こしているすべての非原始的な支柱を覚えるべきです 一般的に、反応フックの依存配列に現れるどんな非原始的な値もmemoizedされなければなりません. 可能であれば、非原始的な小道具を避けるべきであり、任意の原始的な小道具のデフォルトパラメータを使用しないでください.これは、memoizationの必要を除きます. 親コンポーネントが多数の子を持っている場合、テーブルの項目または行のリストを考え、それぞれの子更新親の状態 楽しく、音楽を聴くと、幸運を!
我々が始める前に、用語について整列しましょうので、我々はこの記事を通して同じページにいます
マウント/アンマウント
これらの用語を使用して、コンポーネントがDOMに追加され、その後画面上に描画されるか、DOMと画面から削除された瞬間を記述します.それは常に高価な操作です.
レンダリング
一般的な信念にもかかわらず、“レンダリング”という用語は、画面上のレンダリングとは関係ありません.代わりに、
.render()
反応コンポーネントクラスのメソッド、基本的にメソッドの呼び出しを意味します.機能的なコンポーネントの現代の世界では、レンダリングは文字通りあなたの機能部品を呼ぶことを意味します.この呼び出しは新しいサブツリーとトリガー和解を生成します.また、すべての場合、スクリーン上で更新されなければならないものを決定するためにdiffingとしても知られています.この操作は、実装と反応チームの主張に比べてかなり高価ですO(n)
時間複雑性n
はサブツリー内のノード数です.ここで最も重要な隠れ家は再レンダリングが再実装を引き起こすことはありません.ライフサイクル効果
小道具と状態の間の主な、そして最も重要な違いは、小道具がレンダリングの上で更新されるということである.これは、状態がpropsに依存するたびに、ライフサイクル効果を導入する必要があることを意味します.
const ArticleList = ({ topics }) => {
// This will be initialized on mount only
const [articles, setArticles] = React.useState([]);
// Update list of articles depending on `topics` prop
React.useEffect(() => {
fetchArticles(topics)
.then(data => {
setArticles(data);
});
}, [topics]);
};
プリミティブ/非プリミティブ値
反応中の原始値は、JavaScriptの原始的な値です.あなたがそれらが何であるかについてわからないならば、この記事はあなたのためにあまりにハードコアであるかもしれません.非プリミティブは、残りの関数です.原始的な/非原始的なプロップと原始的な/非原始的な価値ある値を持つことができます.
親指のルールとして選択した場合は、常に原始的な小道具を非原始的な小道具にする必要があります:
// OK
const Address = ({ addressObj }) => {
/** Display address */
};
// Better
const Address = ({
streetLine1,
streetLine2,
locality,
postalCode,
country,
}) => {
/** Display address */
};
「待って?」私は、文字通りあなたの脳が私を今叫んでいるのを聞きます.これを説明すると、この記事の範囲から私たちを混乱させるので、ちょうど原始的な値のまわりにすでに特定の最適化があると言いましょう、そして、最適な最適化は第一に最適化される必要を除いています.まだ確信していない?では、以下の2つのコンポーネントを考え、どれがあなたの呼び出しスタックを爆破するかを推測してください(ヒント:一つだけです).
const Primitive = () => {
const [bool, setBool] = React.useState(false);
// Now, let's have some fun!
React.useEffect(() => {
setBool(false);
});
};
const NonPrimitive = () => {
const [arr, setArr] = React.useState([]);
// Now, let's have even more fun!
React.useEffect(() => {
setArr([]);
});
};
依存配列
ほとんどの反応フックは、第2引数として最初の引数と依存配列としてコールバックを取るので、依存関係配列から値のどれかが変化するならば、コールバックは呼ばれます.例外なく、すべての小文字、またはコールバックで使用されるプロップから派生した値は、依存配列で表示されます.繰り返しますが、この記事は依存関係の配列についてではありませんし、なぜ説明するのも気にしません.しかし、依存関係がなぜオンラインで疲れ果ててしまうのか、良い説明を見つけることができます.私は強く
react-hooks/exhaustive-deps
この規則を守るためにルールを守れ.神話
クール!いくつかの神話のいくつかの反応の開発者を信じて起動し、それらの1つなら、見てみましょう!
インラインハンドラ
これはスーパー既知と同じ時間スーパーダム1です.イベントハンドラをインラインで実行しないでください.
const handleClick = (e) => { /** handle click */ };
return (
<>
{/** BAD */}
<Button onClick={(e) => { /** handle click */ }} />
{/** GOOD */}
<Button onClick={handleClick} />
</>
);
もちろん、これは総BSです!プロップとして渡す前に変数に新しい関数を代入するという事実は絶対に何も変更しません.だけでなくButton
コンポーネントは再描画されますが、関数の新しいインスタンスは、すべてのレンダリングに渡されます.神話は、2 : memoizingフックは、コンポーネントが再レンダリングされるのを防ぐ
それで、解決は簡単です
useCallback
or useMemo
フック、右?悪い!関数の同じmematedインスタンスを渡すとしても、コンポーネントが再描画されないようにしません.実際には、親関数が再描画された場合には、通常の関数コンポーネントを再描画することはありません.反応の回顧化
我々が決心したように、メモ化フックはほとんど無意味です(少し後で彼らについて).したがって、どうやってこの再描画問題を修正するのですか.ミート
React.memo
高次のコンポーネントは、コンポーネント自体をメモして、同じ小道具が提供される場合、それを再レンダリングすることを目的としました.基本的には、より多くのパフォーマーであるプロップ比較をサブツリーの拡散に置き換えることができます.なぜそれがより多くの演奏者が尋ねることができるです.多くの小道具が副木のノードの数と比較して平均的に少ないので、デフォルトで反応するので、非常に軽量操作である浅い比較を使用します.あなたがする必要があるのは
React.memo
:const Button = React.memo(({ label, handler }) => (
<button type="button" onClick={handler}>
{label}
</button>
));
それを理解することが重要ですReact.memo
は、銀弾丸ではなく、別の小道具が渡された場合、再レンダリングから保存されません言い換えれば、あなたが完全にすべての非原始的な小道具を覚えることに完全にコミットする必要がありますmemoizationゲームをプレイした場合、それ以外の場合だけでなく、それは無意味になりますが、あなたのアプリは、それは両方の支柱の比較と各再レンダリングの拡散を実行するように最適化されます.
同じ原理は
React.useMemo
フック-すべての非原始的な値が計算に依存している必要があります.const Page = () => {
const { data: users } = useUsers();
const filteredUsers = users?.filter(filterFn);
return (
<>
{filteredUsers && <RoleList users={filteredUsers} />}
</>
);
};
const RoleList = ({ users }) => {
// Every time new users list provided, group them by role
const roles = React.useMemo(() => groupBy(users, 'role'), [users]);
};
上のコードでusers
からuseUsers
フックは、再描画段階中に永続する値ですfilteredUsers
また、実際には、配列の完全に新しいインスタンスは、すべてのレンダリングを完全にあなたの回想の努力を消して作成されますRoleList
コンポーネントと実際には、以下のパフォーマーを作る.概要
それで、あなたは反応で回想を使うべきですか?それは良い質問です、そして、あなたが現在推測したかもしれないように、答えは単純でありません.しかし、あなたが決めるのを助けるかもしれない2、3の規則を要約しましょう
React.memo
使用法この場合、すべての非原始的な小道具は、記憶されなければなりません.Reference
この問題について(反応における回想とその神話), 我々は、より多くの情報をここで見つけました https://dev.to/snigo/memoization-in-react-and-its-myths-42klテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol