反応パート1における最適化


私たちも最適化が必要ですか?

ほとんどの人々が何もの最初の5秒以内にウェブサイトを離れるように見て、我々は良い場所にいることを確認する必要があります、我々は検査タブからパフォーマンスレポートを実行する灯台を使用することができます.
で我々のウェブサイトを見た後Workiz.com
我々は我々がいくつかのものをリファクタリングし、いくつかの他のものを最適化することを決めたので、改善するいくつかの場所を持って気づいた.

再描画


最初に始めましょう、いつ、反応成分は再描画しますか?
  • 小道具または状態変化のどちらか
  • 親コンポーネントの再レンダリング
  • フックが変わるとき
  • 次のコンポーネントを見てみましょう.
    const Counter = () => {
        const initialCount = 
    parseInt(window.localStorage.getItem("count") ?? "0");
        const [count, setCount] = useState(initialCount);
        const increment = () => {
            window.localStorage.setItem('count', count + 1);
            setCount(count + 1);
        }
        return (
          <>
            Count: {count}
            <button onClick={increment}>+</button>
          </>
        );
      }
    
    私たちには、いくつかの初期状態initialCountを持っているコンポーネントがあります.そして、それはLocalStorageから得られます、そして、機能「増加」は1によってカウントを増やして、それからLocalStorageでそのカウントを保存します.
    読みやすさのために関数の名前を変更します
    const getCountFromLS = () => parseInt(window.localStorage.getItem("count") ?? "0");
    const setCountToLS = (count) =>
    window.localStorage.setItem('count', count);
    
    const initialCount = getCountFromLS();
    const [count, setCount] = useState(initialCount);
    
    「インクリメント」するたびに、最初のレンダリングを越えて使用していなくても、localStorageから初期化カウントが再び読み込まれていることに注目します.
    私たちのために幸運にも、私たちは値またはcallback関数のどちらかを受け入れます.
    この関数は、カウンターのスコープに格納でき、USENTから受け取る初期化コールバックのみからコールできます.
    const initialCount = () => getCountFromLS();
    const [count, setCount] = useState(()=>initialCount());
    
    これは怠惰な初期化と呼ばれています、それは非常に微妙な変化です、しかし、現在、我々は値の代わりにUSENTに機能を与えています.
    const initialCount = () => getCountFromLS();
    const [count, setCount] = useState(initialCount);
    
    コンポーネントが再起動されるたびに、コンポーネントの最初の初期化の間に一度だけ呼び出されるようになります.
    ...誰かが我々のカウンターから離れない限り.
    その場合、彼らがそれに戻るとき、我々は再びカウンタを最初に与える必要があります、そして、もう一つの重いIO操作をします(LocalStorageからものを得ることは高価です).
    コンポーネントのライフサイクルの外で関数コールを動かす必要がある理由は、一般的にコンポーネントを必要とするときの代わりに、アプリケーションの最上位にあるデータをすべて持ってきたいと思います.
    const expensiveInputOperation = getCountFromLS();
    const Counter = () => {
        const [count, setCount] = useState(expensiveInputOperation);
    ...
    
    今、私たちはコンポーネントのライフサイクルの外で高価な操作をしています.
    “ExpensiveInputPperation”は定数であるため、コールバック関数を使用する必要はありません.
    ここで、CoolButtonという新しいコンポーネントを紹介します.
    CoolButtonは、我々はそれをクリックするたびにいくつかの本当に重要な計算を行うだけで非常に基本的なボタンです.
    const CoolButton = ({ clickHandler }) => {
        const handler = () => {
            ReallyImportantCalculation();
            clickHandler();
        };
        return <button onClick={handler}></button>;
      };
    
    カウンターのボタンを新しいボタンで置き換えましょう
    const Counter = () => {
        const [count, setCount] = useState(expensiveInputOperation);
        const increment = () => {
            setCountToLS(count + 1);
            setCount(count + 1);
        }
        return (
          <>
            Count: {count}
            <CoolButton clickHandler={increment}>+</CoolButton>
          </>
        );
      }
    
    今、我々はそれの中にクールボタンを持っているカウンタを持っています.
    ボタンをクリックすると、実際にCOLLEButton内で何も変更されなくても、実際にカウンターとクールボタンが表示されます.
    どうやってこれを止めるの?

    反応する。メモ


    幸運にも、我々のために、反応は我々に子供をそれ自身のペースでレンダリングするのを許すことによって親のレンダリングに対抗する方法を与えて、親の貸し手に頼りません.
    これは反応の使用と同じです.正規の反応の代わりにpurecomponent.コンポーネント
    const CoolButton = React.memo(({ clickHandler }) => {
        const handler = () => {
            ReallyImportantCalculation();
            clickHandler();
        };
        return <button onClick={handler}></button>;
      });
    
    今、私たちはボタンをクリックし、すべてが正しく動作しますが、我々はまだ再クールボタンをレンダリングし続ける.
    メモは、再レンダリングを停止するはずだった?
    これが起こっている理由を理解するためには、小切手や状態が浅い等値に基づいて変化した場合、反応チェックを思い出すことが重要です.
    これは、メモがその小道具のオブジェクトに遭遇するとき、それがオブジェクトが同じかどうかについて話すことができないことを意味します.
    {'test':true} == {'test':true} // FALSE
    
    JavaScriptは、参照が同じであるかどうかを調べます.
    私たちのコンポーネントに戻る、何が起こったの再レンダリングを引き起こした?
    もう一度親コンポーネントを見てみましょう.
    const Counter = () => {
        const [count, setCount] = useState(expensiveInputOperation);
        const increment = () => {
            setCountToLS(count + 1);
            setCount(count + 1);
        }
        return (
          <>
            Count: {count}
            <CoolButton clickHandler={increment}>+</CoolButton>
          </>
        );
      }
    
    たびに我々は再びカウンタをレンダリングボタンをクリックします.
    カウンタをレンダリングすると、すべての関数が再び実行されます.これは、毎回「インクリメント」と呼ばれる新しい匿名関数を取得します.
    私たちは、この新しい“インクリメント”小道具として私たちのCoolButtonに、“インクリメント”を意味する前に、私たちが今持っていると同じ“インクリメント”ではないので、それは私たちのボタンを再度レンダリングするのは当然だ.
    どうしたらいいですか.

    反応する。USERALLBACK


    usecallback救助に!
    この反応フックは、角括弧内の依存関係の1つが変更された場合にのみ変更される機能への参照を受け取ることを保証します.カウンタの再レンダリング時に我々は“インクリメント”機能を覚えるためにこれを使用することができます.

    試み1


    const Counter = () => {
        const [count, setCount] = useState(expensiveInputOperation);
        const increment = useCallback(() => {
            setCountToLS(count + 1);
            setCount(count + 1);
        },[])
        return (
          <>
            Count: {count}
            <CoolButton clickHandler={increment}>+</CoolButton>
          </>
        );
      }
    
    今クールなので、我々はボタンをクリックしますが、それは一度以上では動作しません、なぜですか?
    なぜなら、私たちの関数は決して変更されないからです.したがって、最初にカウントされたカウント値はいずれも同じカウント数になります.
    私たちは単に依存関係の配列に私たちのカウントを追加する必要がありますね?
    まあはい、私たちはそれを行うことができますが、その後、我々は別の“インクリメント”たびに変更を得るだろう.それは、我々が同様に我々のCoolButtonを再レンダリングする必要があることを意味します.正方形に戻る.

    試み2


    幸いにも、setCountは実際にコールバック関数を私たちのUSENT関数と同じように受け取りますが、この1つだけが以前の値を与え、次のものを与えることを期待しています.
    このようなことができます.
     const increment = useCallback(() => {
            setCountToLS(count + 1);
            setCount(prevCount => prevCount + 1);
        },[])
    
    クールなので、setcountはコールバック関数を使います.
    LocalStorageはどうですか?
    それはまだ毎回同じカウントを受け取り、どのように我々はこれを修正することができますか?まあ簡単に十分です-
    だけでなく、setCountコールバックの中にその呼び出しを入れましょう
     const increment = useCallback(() => {
            setCount(prevCount => {
            setCountToLS(prevCount + 1);
            return prevCount + 1;
            })
        },[])
    
    そして今、すべてが正しく動作します!
    const CoolButton = React.memo(({ clickHandler }) => {
        const handler = () => {
            ReallyImportantCalculation();
            clickHandler();
        };
        return <button onClick={handler}></button>;
      });
    const expensiveInputOperation = 
    parseInt(window.localStorage.getItem("count") ?? "0");
    const Counter = () => {
       const [count, setCount] = useState(expensiveInputOperation);
       const increment = useCallback(() => {
       setCount(prevCount => {
              window.localStorage.setItem("count", prevCount + 1);
              return prevCount + 1;
            });
        }, []);
       return (
          <>
            Count: {count}
            <CoolButton clickHandler={increment}>+</CoolButton>
          </>
          );
      }
    
    
    あなたがなぜ私たちがusecallbackで我々の「ハンドラー」機能をラップしていないかについてあなた自身に尋ねているならば、我々はメモ化が無料でないのを覚えていなければなりません.
    プログラミングのすべてはトレードオフです、あなたはいくらかを得るが、他のものを失います.
    原始型<button> , <input> , <div> , などは非常に安いので、我々はすべてのそれらを保存する必要はありませんレンダリングされます.
    我々は、我々がユーザーの経験に影響を与えるときだけ、これらのテクニックを使用しなければなりません.
    次の部分はUSEMMEOについてです、滞在調整!