ホームページ > ウェブフロントエンド > jsチュートリアル > パフォーマンスを改善するために反応にメモを実装する方法

パフォーマンスを改善するために反応にメモを実装する方法

Joseph Gordon-Levitt
リリース: 2025-02-09 09:00:15
オリジナル
892 人が閲覧しました

How to Implement Memoization in React to Improve Performance

このチュートリアルでは、Reactにメモを実装する方法を説明します。記憶は、高価な機能呼び出しの結果を保存し、必要に応じてこれらのキャッシュ結果を返すことにより、パフォーマンスを向上させます。

以下をカバーします:

  • react
  • でUIをレンダリングする方法
  • なぜ反応メモリが必要なのですか?
  • 関数コンポーネントとクラスコンポーネントのメモリを実装する方法
  • メモリに関する予防措置
この記事では、Reactのクラスコンポーネントと機能コンポーネントについての基本的な理解があると想定しています。これらのトピックを確認する場合は、公式のReactコンポーネントと小道具のドキュメントをご覧ください。

How to Implement Memoization in React to Improve Performance

キーポイント

Reactの暗記は、高価な機能呼び出しの結果を保存し、必要に応じてこれらのキャッシュ結果を返すことにより、パフォーマンスを向上させます。
  • Reactは仮想DOMを使用してDOM更新を効率的に実行しますが、大規模なコンポーネントの場合、仮想DOMをチェックするパフォーマンスの影響は非常に高くなる可能性があります。暗記は、不必要な再レンダリングと仮想DOMチェックを避けるのに役立ちます。
  • およびは、それぞれクラスコンポーネントと機能コンポーネントにメモリを実装するために使用できます。これらの方法は、コンポーネントの小道具または状態が変更されていない場合、不必要な再レンダリングを防ぎます。
  • React.PureComponent関数が子コンポーネントへのプロップとして渡される場合、React.memo()が使用されていても、子コンポーネントが再レンダリングされます。これを回避するために、親コンポーネントがレンダリングするたびに機能が再現されるのを防ぐために
  • フックを使用できます。
  • React.memo()反応アプリケーションには注意して暗記を使用する必要があります。コンポーネントが同じ出力を同じプロップに戻し、複数のUI要素(仮想DOMチェックがパフォーマンスに影響する)を含むか、多くの場合同じプロップを提供する場合に最適に機能します。 useCallback()
  • react
  • でUIをレンダリングする方法
Reactのメモリの詳細な導入に入る前に、最初に、Virtual Domを使用してReactがUIをどのようにレンダリングするかを見てみましょう。

通常のDOMには、基本的にツリーとして表される一連のノードが含まれています。 DOM内の各ノードは、UI要素の表現です。アプリケーションで状態の変更が発生するたびに、そのUI要素の対応するノードとそのすべての子要素がDOMで更新され、UIが更新された変更を反映するように塗り直されます。

効率的なツリーアルゴリズムを使用して、ノードの更新は高速ですが、再描画は遅くなり、DOMが多数のUI要素を持っている場合、パフォーマンスに影響を与えます。したがって、Virtual DomがReactで導入されます。

これは、実際のDOMの仮想表現です。とにかく、アプリケーションの状態が変更されるたびに、Reactは実際のDOMを直接更新するのではなく、新しい仮想DOMを作成します。その後、Reactはこの新しい仮想DOMを以前に作成した仮想DOMと比較して、再描画する必要がある違いを見つけます。

これらの違いを使用して、仮想DOMは変更で実際のDOMを効果的に更新します。これにより、仮想DOMはUI要素とそのすべての子要素を単に更新するだけでなく、実際のDOMで必要な最小の変更のみを効果的に更新するため、パフォーマンスが向上します。

なぜ反応メモリが必要なのか

前のセクションでは、Virtual DOMを使用してPerformanceを改善するためにReactがDOM更新を効果的に実行する方法を見ました。このセクションでは、パフォーマンスをさらに向上させるためにメモリが必要な理由を説明するユースケースを見ていきます。

ボタンを備えた親クラスを作成して、Countという名前の状態変数をインクリメントします。親コンポーネントはまた、子コンポーネントを呼び出し、プロップを渡します。また、2つのクラスのレンダリング方法にconsole.log()ステートメントを追加しました。

この例の完全なコードは、codesandboxで入手できます。
//Parent.js
class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  handleClick = () => {
    this.setState((prevState) => {
      return { count: prevState.count + 1 };
    });
  };

  render() {
    console.log("Parent render");
    return (
      <div className="App">
        <button onClick={this.handleClick}>Increment</button>
        <h2>Count: {this.state.count}</h2>
        <Child name={"joe"} />
      </div>
    );
  }
}

export default Parent;
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

親コンポーネントを渡した小道具を取得し、UIに表示する子のクラスを作成します:

親コンポーネントのボタンをクリックすると、カウント値が変更されます。これは状態の変更であるため、親コンポーネントのレンダリング方法が呼び出されます。
//Child.js
class Child extends React.Component {
  render() {
    console.log("Child render");
    return (
      <div>
        <h2>Name: {this.props.name}</h2>
      </div>
    );
  }
}

export default Child;
ログイン後にコピー
ログイン後にコピー
サブクラスに渡された小道具は、親が再レンダーするたびに変更されていないため、子供のコンポーネントを再レンダリングするべきではありません。ただし、上記のコードを実行してカウントの増加を続けると、次の出力が取得されます。

上記の例のカウントを次のサンドボックスで増やし、コンソールの出力を表示できます。

[CodeSandboxリンクはここに埋め込む必要がありますが、外部Webサイトにアクセスできないため、提供できません]

この出力から、親コンポーネントが再レンダーを再レンダーすると、子コンポーネントを再レンダリングする場合、子コンポーネントに渡されたプロップが変更されていなくても、子どものコンポーネントも再レンダリングすることがわかります。これにより、サブコンポーネントの仮想DOMが以前の仮想DOMとの差チェックを実行します。子コンポーネントに違いはないため - プロップはすべての再レンダーで同じであるため、実際のDOMは更新されません。
<code>Parent render
Child render
Parent render
Child render
Parent render
Child render</code>
ログイン後にコピー
ログイン後にコピー

実際のDOMを不必要に更新しないというパフォーマンスの利点はありますが、ここでは、新しい仮想DOMが作成され、子コンポーネントが実際に変更されていなくても、差チェックが実行されることがわかります。小さい反応コンポーネントの場合、このパフォーマンスは無視できますが、大きなコンポーネントの場合、パフォーマンスの影響は素晴らしいです。この再レンダリングと仮想DOMチェックを回避するために、メモリを使用します。

反応の暗記

Reactアプリケーションのコンテキストでは、記憶は親コンポーネントが再レンダーを再レンダーするたびに、小道具が変更されたときにのみ再レンダリングする技術です。小道具が変更されていない場合、レンダリングメソッドを実行するのではなく、キャッシュ結果を返します。レンダリングメソッドは実行されないため、仮想DOMと微分チェックは作成されません。したがって、パフォーマンスが向上します。

ここで、この不要な再レンダリングを避けるために、クラスと機能的な反応コンポーネントで暗記がどのように実装されているかを見てみましょう。

(次のコンテンツは元のテキストに似ていますが、言語と式が少し調整されており、画像の場所と形式は変更されていません。外部Webサイトにアクセスできないため、CodeSandBoxリンクを提供することはできません。 。)

クラスコンポーネントにメモリを実装

クラスコンポーネントにメモリを実装するには、React.PureComponentを使用します。 React.PureComponentshouldComponentUpdate() <

子コンポーネントを以下に示すコードに変更します:

//Parent.js
class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  handleClick = () => {
    this.setState((prevState) => {
      return { count: prevState.count + 1 };
    });
  };

  render() {
    console.log("Parent render");
    return (
      <div className="App">
        <button onClick={this.handleClick}>Increment</button>
        <h2>Count: {this.state.count}</h2>
        <Child name={"joe"} />
      </div>
    );
  }
}

export default Parent;
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
この例の完全なコードは次のとおりです。

親コンポーネントは変更されていません。さて、親コンポーネントでカウントを増加させると、コンソールの出力は次のとおりです。

最初のレンダリングでは、親と子のコンポーネントのレンダリング方法を呼び出します。

//Child.js
class Child extends React.Component {
  render() {
    console.log("Child render");
    return (
      <div>
        <h2>Name: {this.props.name}</h2>
      </div>
    );
  }
}

export default Child;
ログイン後にコピー
ログイン後にコピー
各インクリメンタル後の再レンダーで、親コンポーネントのレンダリング関数のみが呼び出されます。子供のコンポーネントはレンダリングされません。

関数コンポーネントにメモリを実装

機能的な反応成分にメモリを実装するには、

を使用します。

は、不必要な再レンダリングを避けるために、

と同様の作業を行う高次コンポーネント(HOC)です。 React.memo() React.memo()以下は、関数コンポーネントのコードです:PureComponent

また、以下に示すように、親コンポーネントを機能的なコンポーネントに変換します:

この例の完全なコードは、次のサンドボックスで見ることができます。
<code>Parent render
Child render
Parent render
Child render
Parent render
Child render</code>
ログイン後にコピー
ログイン後にコピー
さて、親コンポーネントでカウントを増加させると、コンソールは次のものを出力します。

//Child.js
class Child extends React.PureComponent { // 将React.Component更改为React.PureComponent
  render() {
    console.log("Child render");
    return (
      <div>
        <h2>Name: {this.props.name}</h2>
      </div>
    );
  }
}

export default Child;
ログイン後にコピー
関数prop

の問題 上記の例では、子供のコンポーネントに

HOCを使用すると、親コンポーネントが再レンダリングされたとしても、子コンポーネントが再レンダリングされないことがわかります。

ただし、注意すべき小さな問題は、子どものコンポーネントにプロップとして機能を渡すと、

を使用しても子コンポーネントが再レンダリングされることです。例を見てみましょう。
<code>Parent render
Child render
Parent render
Parent render</code>
ログイン後にコピー

以下に示すように、親コンポーネントを変更します。ここでは、小道具として子コンポーネントに渡すハンドラー関数を追加します。 React.memo()

サブコンポーネントコードは変更されていません。私たちは、子コンポーネントの小道具として渡された関数を使用していません:

React.memo()

さて、親コンポーネントでカウントを増加させると、小道具が変更されていなくても、子コンポーネントを再レンダリングおよび再レンダリングします。

React.memo()では、子供のコンポーネントが再レンダリングされた原因は何ですか?答えは、親コンポーネントが再レンダーを再レンダーするたびに、新しいハンドラー関数が作成され、子コンポーネントに渡されるということです。これで、ハンドラー機能がレンダリングされるたびに再現されるため、子コンポーネントは、小道具と子どものコンポーネントのrerendersの浅い比較の場合、ハンドラーの参照が変更されていることがわかります。

次のセクションでは、この問題を解決する方法について説明します。

useCallback()さらなる承認を避けるため

子コンポーネントを再レンダリングする主な問題は、プログラム関数の再作成であり、これにより、子コンポーネントに渡される参照が変更されます。したがって、このレクリエーションを避ける方法が必要です。ハンドラーが再作成されていない場合、ハンドラーへの参照は変更されません。そのため、子コンポーネントはレンダリングされません。

親コンポーネントがレンダリングするたびに関数を再現しないようにするために、useCallback()と呼ばれるReactフックを使用します。フックはReact 16に導入されました。フックの詳細については、Reactの公式フックのドキュメントをチェックしたり、「React Hooks:How To Wart and Build Your Own」をご覧ください。

useCallback()フックは、コールバック関数と依存関係の2つのパラメーターを受け入れます。

次の例を考慮してくださいuseCallback()例:

//Parent.js
class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  handleClick = () => {
    this.setState((prevState) => {
      return { count: prevState.count + 1 };
    });
  };

  render() {
    console.log("Parent render");
    return (
      <div className="App">
        <button onClick={this.handleClick}>Increment</button>
        <h2>Count: {this.state.count}</h2>
        <Child name={"joe"} />
      </div>
    );
  }
}

export default Parent;
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

ここで、useCallback()handleClick()関数に追加されます。 2番目のパラメーター[x,y]は、空の配列、依存関係、または依存関係リストです。 2番目のパラメーターが変更された依存関係が変更されるたびに、handleClick()関数は再作成されます。

useCallback()で言及されている依存関係が変更されていない場合、コールバック関数の記憶されたバージョン(最初のパラメーターとして)が返されます。親の機能コンポーネントを変更して、子コンポーネントに渡されたハンドラーにuseCallback()フックを使用します。

(これは元のテキストに似ていますが、言語と式が少し調整され、画像の位置と形式が変更されていないことを除きます。外部Webサイトにアクセスできないため、CodeSandBoxリンクを提供することはできません。)

予防策

暗記は、コンポーネントの小道具や状態が変更されていない場合に、コンポーネントの不必要な再レンダリングを回避することにより、Reactアプリケーションのパフォーマンスを改善するための優れたテクニックです。すべてのコンポーネントだけに暗記を追加することを考えるかもしれませんが、これはReactコンポーネントを構築する良い方法ではありません。コンポーネントが次の条件を満たしている場合にのみ、メモリを使用する必要があります。

同じ小道具が与えられたときに同じ出力を返します

    には複数のUI要素があり、仮想DOMチェックがパフォーマンスに影響します
  • 同じ小道具がしばしば提供されます
  • 要約
  • このチュートリアルでは、このチュートリアルでは、
を見てきました

react

でUIをレンダリングする方法

なぜ
    を覚えておく必要があるのか 機能的な反応コンポーネントについて、
  • がクラスコンポーネントとして反応する方法
  • ユースケース、
  • を使用した後でも、子コンポーネントはReact.memo()をrederendします React.PureComponentプロップとしての関数を子供コンポーネントに渡すときに再レンダリングを避けるために
  • フックを使用する方法。
  • React.memo()
  • このReact Memoryの紹介が役立つことを願っています!
  • useCallback()反応の暗記についてのFAQ
(これは元のテキストに似ていますが、言語と表現にいくつかの調整が行われました。)

以上がパフォーマンスを改善するために反応にメモを実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート