React.memo、useMemo、useCallbackの役割と違い


Reactは、構成部品をレンダリングした後、Dom更新を決定するために、以前にレンダリングした結果と比較します.このとき、再レンダリングを必要としない要素のレンダリングを防止し、更新速度を向上させる方法がいくつかあります.正しいキャラクタと区別を区別するために、まとめます.

1. React.memo


React.memoはHigher Order Components(HOC)です.
(構造内の関数で、受信素子をパラメータとして新しい素子を返します)
  • HOC例(authでページ権限をチェック)
  • // Auth라는 HOC를 통해 권한에 따라 라우팅 처리
    function App() {
      return (
        <Suspense fallback={<div>Loading...</div>}>
          <NavBar />
          <div>
            <Switch>
              <Route exact path="/" component={Auth(LandingPage, null)} />
              <Route exact path="/login" component={Auth(LoginPage, false)} />
              <Route exact path="/register" component={Auth(RegisterPage, false)} />
              <Route
                exact
                path="/video/upload"
                component={Auth(VideoUploadPage, true)}
              />
              <Route
                exact
                path="/video/:videoId"
                component={Auth(VideoDetailPage, null)}
              />
              <Route
                exact
                path="/subscription"
                component={Auth(SubscriptionPage, null)}
              />
            </Switch>
          </div>
          <Footer />
        </Suspense>
      );
    }
    
    export default App;
    // Auth validation example
    import React, { useEffect } from 'react';
    import { auth } from '../_actions/user_actions';
    import { useSelector, useDispatch } from "react-redux";
    
    export default function (SpecificComponent, option, adminRoute = null) {
        function AuthenticationCheck(props) {
    
            let user = useSelector(state => state.user);
            const dispatch = useDispatch();
    
            useEffect(() => {
                //To know my current status, send Auth request 
                dispatch(auth()).then(response => {
                    //Not Loggined in Status 
                    if (!response.payload.isAuth) {
                        if (option) {
                            props.history.push('/login')
                        }
                        //Loggined in Status 
                    } else {
                        //supposed to be Admin page, but not admin person wants to go inside
                        if (adminRoute && !response.payload.isAdmin) {
                            props.history.push('/')
                        }
                        //Logged in Status, but Try to go into log in page 
                        else {
                            if (option === false) {
                                props.history.push('/')
                            }
                        }
                    }
                })
    
            }, [])
    
            return (
                <SpecificComponent {...props} user={user} />
            )
        }
        return AuthenticationCheck
    }
    一般的なコンポーネントはpropsをUIに伝達するが,HOCは反応器のAPIではなく,反応器がコンポーネントを構成するモードであると考えられる.
    既定では、リアクターはShallow copyを実行します.(参照値のみ比較)
    つまり、ステータスが変更されたり、新しい構成部品がレンダリングされたりすると、ライトコピーは同じ値かどうかを決定し、レンダリングするかどうかを決定します.
    したがって、元のタイプのオブジェクト、配列、関数などの参照タイプが同じ参照でない場合は、新しい値と判断されます.
    たとえば,素子の状態が変化すると,同じ値のpropsでも浅い複製で新しい値として認識される.
    同じpropsを受け取ったコンポーネントが同じ結果をレンダリングしている場合、React.memoを使用すると、不要な構成部品のレンダリングを防止できます.
    React.memoを使用すると、前のツールと同じツールを入力すると、レンダープロセスがスキップされ、最近のレンダー結果が再使用されます.
    React.memoは伝達されたアイテムを変更するかどうかだけをチェックします.ただし、構成部品内部でusStateなどのhookを使用すると、ステータスが変更されると再レンダリングされます.
    props自体はprimite typeなので、同じ値しか使用できませんが、関数やオブジェクトは使用できません.
    したがって、useCallback、useMemoで特定のpropsに依存することで、レンダリング回数を減らすことができる.
    でも!
    useCallbackのみでは、下流コンポーネントの再レンダリングを阻止できません.
    親コンポーネントで定義されているuseCallbackは、子コンポーネントで使用されている場合は無効です.
    サブエレメントにuseCallbackの論理処理がない場合は、親コンポーネントが再レンダリングされるかどうかによってのみレンダリングされます.
    すなわち,サブエレメントは「参照同一性に依存するpureComponent」でなければ意味がない.
  • React.memoの使い方
  • export default React.memo(component);
    既定では、書き出し時に構成部品名がReact.memoに囲まれています.
    shouldComponentUpdateを内蔵し、再レンダリングを防止するために浅いコピーを実行します.
    方法は、サンプルコードなどのモジュール化された構成部品をエクスポートすることです.memoで包んでください.
    この方法は、[同じpropsを使用してレンダリングを頻繁に行う構成部品]と[レンダリングで大量のリソースを消費する構成部品]に使用します.
    しかし、盲目的に使うべきではない.場合によっては不要な比較演算しか追加されないためです.
    上記の方法に加えて、以下の例を用いることができる.
    // example
    const MyComponent = React.memo((props) => {
    	return (/*컴포넌트 렌더링 코드*/)}
    );
    転送されたpropsを変更するかどうかは、浅い比較として比較されるため、objectでは同じ値が参照されるかどうかを比較します.
    (不変性を考慮する必要がある)
    この比較方法をカスタマイズするには、次の手順に従います.memoの2番目のパラメータを入れればいいです.
    function MyComponent(props) {
      /* 컴포넌트 로직 */
    }
    function areEqual(prevProps, nextProps) {
      /*
      전달되는 nextProps가 prevProps와 같다면 true를 반환, 같지 않다면 false를 반환해 준다.
      */
    }
    
    export default React.memo(MyComponent, areEqual);

    2. useMemo


    useMemoは、コメントされた値を返すhookです.
    useMemoは、以前の値を記憶し、条件に従って回収してパフォーマンスを最適化するために使用されます.(特定の値を再使用)
  • useMemo用法
  • const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
    関数と依存項目をパラメータで渡します.このとき、2番目のパラメータに渡される依存パラメータのいずれかの値が変化すると、1番目のパラメータの関数が再実行されます.これにより、レンダリングのたびに不要な計算が回避されます.Dependenciesパラメータが渡されない場合は、再計算のたびに返されます.
    特定の状況でのみ実行できる関数です.この関数は、コンポーネントのレンダリング条件に従って継続的に実行される場合に使用できます.
    次の例です.
    const count = countActiveUsers(users);
    return (
    	<>
        	<CreateUser
              username={username}
              email={email}
              onChange={onChange}
              onCreate={onCreate}
            />
            <UserList users={users} onRemove={onRemove} onToggle={onToggle} />
            <div>숫자 : {count}</div>
        </>
    );
    この場合、countActiveUserはユーザーが変化した場合にのみ再実行されるべきですが、サンプルコードのように論理を記述すると、各ステータスの変化はcountを再呼び出して実行されます.
    //const count = countActiveUsers(users);
    const count = useMemo(() => countActiveUsers(users), [user]);
    return (
    	<>
        	<CreateUser
              username={username}
              email={email}
              onChange={onChange}
              onCreate={onCreate}
            />
            <UserList users={users} onRemove={onRemove} onToggle={onToggle} />
            <div>숫자 : {count}</div>
        </>
    );
    この場合はuserMemoを使用します.useEffectは使い方と似ています.useMemoの動作条件を設定し、その変数に私が望む場合を登録すればよい.
  • 注意事項
    すべての関数をuserMemoでカプセル化すると、リソースも浪費されるため、パフォーマンスの最適化が必要な年定数が多い場所で使用することが望ましい.
  • userefとの違い
    useMemoはdepsが変更される前に値を記憶したり、実行後に値を保持したりする役割を果たすことができます.複雑な関数の戻り値を覚えます.これはuserefとは異なります.userefが値を記憶する場合、userMemoは複雑な関数のreturn値を記憶するために使用されます.

    3. useCallback


    useCallbackは、レンダリングパフォーマンスに応答するためのHookです.
    構成部品をレンダリングするたびに、内部で使用される関数が再作成されます.
    新しく作成した関数をPropとしてサブエレメントに渡すと、不要な再レンダリングが発生する可能性があります.(特定の関数を再使用)
  • useCallbackの使い方
    次に、useCallback hookが必要な例を示します.
  • import React, {useSatate} from 'react';
    import {saveToServer} from './api';
    import UserEdit from './UserEdit';
    
    function Profile(){
      const [name, setName] = useState('');
      const [age, setAge] = useState(0);
      
      return (
        <div>
          <p>{`name is ${name}`}</p>
          <p>{`age is ${age}`}</p>
          <UserEdit 
            onSave={() => saveToServer(name, age)}
            setName={setName}
            setAge={setAge}
          />
        </div>
      );
    }
    Profile構成部品をレンダリングするたびに、新しい関数はUserEdit構成部品のonSave属性値として渡されます.
    UserEdit構成部品から復元します.memoを使用すると、転送されたPropは常に変更されるため、不要なレンダリングが発生します.
    onSaveのプロパティ値は、名前またはage値が変更されない限り、常に同じである必要があります.
    useCallbackを使用すると、次の問題を回避できます.
    function Profile(){
      const [name, setName] = useState('');
      const [age, setAge] = useState(0);
      const onSave = useCallback(() => saveToServer(name, age), [name, age]);
      return (
        <div>
        	<p>{`name is ${name}`}</p>
        	<p>{`age is ${age}`}</p>
    	<UserEdit onSave={onSave} setName={setName} setAge={setAge} />
        </div>
      );
    }
    useMemoと同様に、最初のパラメータで関数を渡し、2番目のパラメータでDependenciesを渡します.
    伝達された依存性因子が変更されていない場合、以前に作成した関数は再使用されます.
    つまり、nameとageの値が変わらなければ、
    UserEdit構成部品のonSave属性値は、再レンダリングを防ぐために常に同じ関数を渡すことができます.
    useMemoと同様に、各関数はuseCallbackとして定義され、条件を追加すればよい.もちろん、これらの条件は関数で使用されるすべての変数でなければなりません.
    関数をpropsとしてサブコンポーネントに提供する場合は、useCallbackを使用して再レンダリングしないことを確認します.

    整理する

  • 共通点
  • React.memo、useMemo、およびuseCallbackは、不要なレンダリングまたは演算を制御するためにパフォーマンスを最適化することを目的としています.
  • 差異
  • React.memoはHOC、useMemoとuseCallbackはhookです.
  • React.memoはHOCなのでクラス素子も関数素子も使えますが、userMemoはhookなので関数素子でしか使えません.
  • useMemoの目的は、関数演算量が大きい場合に以前の結果値を再利用することであり、useCallbackの目的は、関数再生を防止することである.