componentWillReceivePropsではなく、ライフサイクルメソッドgetDerivedStateFromPropsを使用する方法


142

以下のように見えますcomponentWillReceiveProps全く新しいライフサイクルメソッドの賛成で、今後のリリースで段階的に廃止される予定であるgetDerivedStateFromProps静的getDerivedStateFromPropsを()

調べてみるthis.propsnextProps、のようにとを直接比較できないようになっていますcomponentWillReceiveProps。これを回避する方法はありますか?

また、オブジェクトを返すようになりました。私は戻り値が本質的にであると仮定するのは正しいthis.setStateですか?

以下は私がオンラインで見つけた例です:状態はprops / stateから派生しました

class ExampleComponent extends React.Component {
  state = {
    derivedData: computeDerivedState(this.props)
  };

  componentWillReceiveProps(nextProps) {
    if (this.props.someValue !== nextProps.someValue) {
      this.setState({
        derivedData: computeDerivedState(nextProps)
      });
    }
  }
}

class ExampleComponent extends React.Component {
  // Initialize state in constructor,
  // Or with a property initializer.
  state = {};

  static getDerivedStateFromProps(nextProps, prevState) {
    if (prevState.someMirroredValue !== nextProps.someValue) {
      return {
        derivedData: computeDerivedState(nextProps),
        someMirroredValue: nextProps.someValue
      };
    }

    // Return null to indicate no change to state.
    return null;
  }
}

回答:


96

除去についてcomponentWillReceiveProps:あなたは、の組み合わせでその用途を扱うことができるはずgetDerivedStateFromPropscomponentDidUpdate、ご覧のブログ記事に反応例の移行のために。そして、はい、によって返されたオブジェクトは、にgetDerivedStateFromProps渡されたオブジェクトと同様に状態を更新しますsetState

プロップの古い値が本当に必要な場合は、次のようにして常に状態にキャッシュできます。

state = {
  cachedSomeProp: null
  // ... rest of initial state
};

static getDerivedStateFromProps(nextProps, prevState) {
  // do things with nextProps.someProp and prevState.cachedSomeProp
  return {
    cachedSomeProp: nextProps.someProp,
    // ... other derived state properties
  };
}

状態に影響を及ぼさないものはすべてに入れることができ、非常に低レベルのものcomponentDidUpdateさえありgetSnapshotBeforeUpdateます。

更新:新しい(および古い)ライフサイクルメソッドの感触をつかむには、react-lifecycle-visualizerパッケージが役立つ場合があります。


1
ああ、私は質問を台無しにした。私が実際に言ったのはcomponentWillReceiveProps
Andrew

2
以前の小道具を保持するために自分の状態を使用することを考えていましたが、それを実装するために必要な余分なコードとロジックを本当に避けたかったのです。あなたが育てている他の事柄のいくつかを調べます。どうもありがとう!
アンドリュー

4
以前の小道具を状態に保存する必要があることは、この理解しにくいReact APIの変更に対する定型的な回避策にすぎません。多くの開発者の目には、これはアンチパターンとリグレッション変更のように見えます。Oblosysを批判するのではなく、Reactチーム。
AxeEffect

2
@AxeEffectこれはgetDerivedStateFromProps、メモ化を意図したものではなかったためです。代わりに推奨されるアプローチについて説明した以下の私の回答を参照してください。
ダンアブラモフ2018年

それはタイプミスですか?見逃しました...か?つまり、状態オブジェクト全体を返すか、必要な部分のみを返すかです。
プログラマー

51

我々は、最近に投稿反応しほとんどの場合には必要のないgetDerivedStateFromPropsすべてで

一部の派生データを計算する場合は、次のいずれかを実行します。

  1. 中に入れて render
  2. または、再計算にコストがかかる場合は、などのメモ化ヘルパーを使用しmemoize-oneます。

これが最も単純な「後」の例です。

import memoize from "memoize-one";

class ExampleComponent extends React.Component {
  getDerivedData = memoize(computeDerivedState);

  render() {
    const derivedData = this.getDerivedData(this.props.someValue);
    // ...
  }
}

詳細については、ブログ投稿のこのセクションをご覧ください。


45
それが必要でないなら、広大な大多数の場合、私は、これは、そのようなひどく必要な変化であった作業の何千ものプロジェクトを中断します1を驚かせています。Reactチームがエンジニアリングから始めたようです。
スカ

39
componentWillReceivePropsからgetDerivedStateFromPropsに変更します。壊れているのではなく、既存のすべてのコードをリファクタリングする必要があり、非常に時間がかかります。また、ほとんどの場合それを使用するべきではないと言うので、ほとんどメリットがないようです。そもそも、使用すべきではない何かのためにAPIを変更するという煩わしさを経験する理由。
スカ

4
ダン・アブラモフからのこのコメントへの返答が大好きです。
Louis345

6
@DanAbramovなぜこの変更が行われたのかについての答えはありますか?
ペトロスキリアコウ

3
実際、私たちのプロジェクトではこれがよく使われています。新しいデータがダウンしたときに画面にスナックバーのようなものを表示するための1つの例。componentWillReceivePropsシンプルでうまくいきました。この静的なゴミのためにそれを削除する理由...
Oliver Dixon

6

ダン・アブラモフが述べたように

レンダー内で実行する

私たちは実際に、メモ計算でこの方法を使用して、あらゆる種類の代理小道具を状態計算に使用しています。

私たちのコードはこのように見えます

// ./decorators/memoized.js  
import memoizeOne from 'memoize-one';

export function memoized(target, key, descriptor) {
  descriptor.value = memoizeOne(descriptor.value);
  return descriptor;
}

// ./components/exampleComponent.js
import React from 'react';
import { memoized } from 'src/decorators';

class ExampleComponent extends React.Component {
  buildValuesFromProps() {
    const {
      watchedProp1,
      watchedProp2,
      watchedProp3,
      watchedProp4,
      watchedProp5,
    } = this.props
    return {
      value1: buildValue1(watchedProp1, watchedProp2),
      value2: buildValue2(watchedProp1, watchedProp3, watchedProp5),
      value3: buildValue3(watchedProp3, watchedProp4, watchedProp5),
    }
  }

  @memoized
  buildValue1(watchedProp1, watchedProp2) {
    return ...;
  }

  @memoized
  buildValue2(watchedProp1, watchedProp3, watchedProp5) {
    return ...;
  }

  @memoized
  buildValue3(watchedProp3, watchedProp4, watchedProp5) {
    return ...;
  }

  render() {
    const {
      value1,
      value2,
      value3
    } = this.buildValuesFromProps();

    return (
      <div>
        <Component1 value={value1}>
        <Component2 value={value2}>
        <Component3 value={value3}>
      </div>
    );
  }
}

その利点は、大量の比較ボイラープレートを内部でコーディングする必要がないこと、getDerivedStateFromPropsまたはcomponentWillReceivePropsコンストラクター内でコピーと貼り付けの初期化をスキップできることです。

注意:

このアプローチは、コンポーネントのライフサイクルで処理する必要がある内部状態ロジックがある場合に、プロップを状態にプロキシするためにのみ使用されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.