反応の効用における参照等価性の理解


こんにちは、仲間読者!
このポストでは、私はそれがオブジェクトがあるとき、どのようにUseEffectが依存関係であるかについて議論するつもりです.
注意: UseEffectsについていくつかの重要な概念を知っているという前提があります.だから、あなたは本当に基本を知っていない場合は、私は最初にお勧めしますread the React docs この問題について.

参照平等


プログラミング言語の大部分の比較について話をするとき,2つのトピックについて述べた.
JavaScriptの世界では、これも真実です.文字列や数字のようなプリミティブ型を使用して値を比較したり、オブジェクトを処理するときに参照を比較できます.

価値比較


これは最も簡単なコンセプトです.2つの値が等しい場合、Boolean比較結果true . これはJavaScript(文字列、数値、ブール演算)の最も一般的なプリミティブ型で動作します.
const a = 1;
const b = 1;
const c = 2;
console.log(a === b); // true
console.log(b === c); // false

const d = 'hello';
const e = 'hello';
const f = 'bye';
console.log(d === e); // true
console.log(e === f); // false

参照による比較


このタイプの比較は、オブジェクトがどこに位置するかを考慮する.つのオブジェクトが同じ場所を指している場合、それらは等しいです.次のスキーマをチェックします.

つのオブジェクトが同じ値を持つ同じプロパティを持つ場合でも、同じメモリ位置に配置されない限り、それらは等しくなりません.次のコードをブラウザのdevtoolsで実行して、次のコードを確認できます.
const obj1 = { animal: 'dog' };
const obj2 = { animal: 'dog' };
const obj3 = obj1

console.log(obj1 === obj1) // true
console.log(obj1 === obj2) // false
console.log(obj2 === obj3) // false
console.log(obj1 === obj3) // true

反応の使用効果の比較


前に、比較の種類についての比較を念頭に置いて、その概念を反応のフックUseeffectにもたらしましょう.
したがってReact's docs , このフックは以下のように定義できます:

The Effect Hook lets you perform side effects in function components. Data fetching, setting up a subscription, and manually changing the DOM in React components are all examples of side effects. Whether or not you’re used to calling these operations “side effects” (or just “effects”), you’ve likely performed them in your components before.


特定の変更の後に効果を実行する必要がある場合、依存性の配列であるフックの2番目の引数を使用する必要があります.
useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]); // Only re-run the effect if count changes
依存関係が変化するたびに、UseEffect内部のコールバックが実行され、このプロセスでは比較がどのように行われるかを知ることが重要です.
を返します.string or number , 値による比較があります、さもなければ、参照による比較があります.
依存関係に関しては、UseEffectの機能について多くのエラーがありました.例えば、あなたのバックエンドがクラウドサービスでホストされるならば、あなたはお金の損失で起こるかもしれないAPIへの無限ループまたは複数の呼び出しであなた自身を罠にかけるかもしれません.これらの問題を緩和するためには、これらの依存関係をできるだけ安定に保つことが重要である.
では、いくつかの例を見てみましょう.

  • USEffect +値の比較:この例では、単純なカウントコンポーネントを表示しますcount 状態変化それが数であるように、これが本当であるならば、前の数と新しい数が異なるならば、反応は単に反応しますuseEffect が呼ばれる.
  • const ValueComparison = () => {
      const [count, setCount] = useState(0);
    
      useEffect(() => {
        document.body.append(`Whoa! My count is now: ${count}`);
        var br = document.createElement('br');
        document.body.appendChild(br);
      }, [count]);
    
      return <button onClick={() => setCount(count + 1)}>Click me to count</button>;
    };
    

  • UseEffect +リファレンス比較(1):次の例では、共通の問題が表示されます.これは直接変更されるオブジェクトの状態を示しますが、何もレンダリングされません.チェックアウト:
  • const ReferenceComparison1 = () => {
      const [animalObj, setAnimalObj] = useState({ animal: 'dog' });
    
      const handleChange = () => {
        animalObj.animal = animalObj.animal === 'cat' ? 'dog' : 'cat';
        setAnimalObj(animalObj);
      };
    
      useEffect(() => {
        document.body.append(`I am this animal: ${animalObj.animal}`);
        var br = document.createElement('br');
        document.body.appendChild(br);
      }, [animalObj]);
    
      return <button onClick={handleChange}>Click me to change the animal</button>;
    };
    

    あなたは、あなた自身に尋ねているかもしれませんが、困惑しました:しかし、州は変わりました!今、動物は猫であるべきです!
    まあいいえ.オブジェクト固有のプロパティを変更します.参照して、オブジェクトの比較を参照して行われますか?したがって、いくつかのプロパティが変更されても、メモリ内のオブジェクトの参照は同じままです.
    これを修正するには、新しいオブジェクトをsetAnimalObj , この新しいオブジェクトが新しいメモリの場所を指していることを意味するので、依存関係が変更され、useEffect ウィルファイア
    const ReferenceComparison1 = () => {
      const [animalObj, setAnimalObj] = useState({ animal: 'dog' });
    
      const handleChange = () => {
        setAnimalObj({
          ...animalObj,
          animal: animalObj.animal === 'cat' ? 'dog' : 'cat',
        });
      };
    
      useEffect(() => {
        document.body.append(`I am this animal: ${animalObj.animal}`);
        var br = document.createElement('br');
        document.body.appendChild(br);
      }, [animalObj]);
    
      return <button onClick={handleChange}>Click me to change the animal</button>;
    };
    

  • UseEffect +リファレンス比較( 2 ) :親の子要素の関係を示す例を次に示します.
  • // Here is the parent component that renders an animal list and a button that increments a counter
    const ReferenceComparison2 = () => {
      const [count, setCount] = useState(0);
      const animalList = [
        { animal: 'dog' },
        { animal: 'cat' },
        { animal: 'turtle' },
      ];
    
      return (
        <React.Fragment>
          <ChildComponent data={animalList} />
          <span>Count: {count}</span>
          <button onClick={() => setCount(count + 1)}>Increment count</button>
        </React.Fragment>
      );
    };
    
    // Here is the child component, responsible for rendering the list used by parent component
    const ChildComponent = ({ data }: ChildComponent1Props) => {
      useEffect(() => {
        document.body.append(`Child rendered! Data has changed!`);
        var br = document.createElement('br');
        document.body.appendChild(br);
      }, [data]);
    
      return (
        <ul>
          {data.map((item, index) => (
            <li key={index}>{item.animal}</li>
          ))}
        </ul>
      );
    };
    
    上記のコードを実行すると、子要素がボタンをクリックするたびに再構築されますが、カウンタとリストは独立していることがわかります.

    これは、カウンタが更新されるたびに、親コンポーネントが再構築されるので、この関数は発生します.したがって、この関数は再び呼び出されますanimalList 変数.最後に、子コンポーネントはこの変更を認識して実行しますuseEffect .

    これは多くの方法で解決することが可能です、それらの2つを見ましょう.以下の最初の解決策は単に配列データをコンポーネント関数の外部に移動させるため、オブジェクト参照は決して変更されません.
    const animalList = [{ animal: 'dog' }, { animal: 'cat' }, { animal: 'turtle' }];
    
    const ReferenceComparison2 = () => {
      const [count, setCount] = useState(0);
    
      return (
        <React.Fragment>
          <ChildComponent data={animalList} />
          <span>Count: {count}</span>
          <button onClick={() => setCount(count + 1)}>Increment count</button>
        </React.Fragment>
      );
    };
    
    番目の可能な解決策はuseMemo . このフックは依存関係が変更されない限り同じ値を保持します:
    const ReferenceComparison2 = () => {
      const [count, setCount] = useState(0);
      const animalList = useMemo(
        () => [{ animal: 'dog' }, { animal: 'cat' }, { animal: 'turtle' }],
        []
      );
    
      return (
        <React.Fragment>
          <ChildComponent data={animalList} />
          <span>Count: {count}</span>
          <button onClick={() => setCount(count + 1)}>Increment count</button>
        </React.Fragment>
      );
    };
    
    今私たちの子コンポーネントは実行されませんuseEffect , データ依存には安定した参照があります.

    ラッピング


    使用するとき、参照の等級がどのように働くかを見ましたuseEffect . オブジェクト、配列、関数に依存している場合、特に依存関係に注目することは常に重要です.
    同じ効果が何度も実行されるとき、あなたは時々トラブルを見つけるかもしれません.これが起こるならば、依存関係をチェックアウトして、彼らが安定しているならば、思い出してください.
    あなたの意見を公開したり、私に何かを聞いてコメントのセクションを使用してお気軽に!ありがとう