プロップからの反応コンポーネント初期化状態


204

Reactでは、これら2つの実装の間に実際の違いはありますか?一部の友人は、FirstComponentがパターンだと言っていますが、その理由はわかりません。レンダリングが1回だけ呼び出されるため、SecondComponentはより単純に見えます。

最初:

import React, { PropTypes } from 'react'

class FirstComponent extends React.Component {

  state = {
    description: ''
  }

  componentDidMount() {
    const { description} = this.props;
    this.setState({ description });
  }

  render () {
    const {state: { description }} = this;    
    return (
      <input type="text" value={description} /> 
    );
  }
}

export default FirstComponent;

第二:

import React, { PropTypes } from 'react'

class SecondComponent extends React.Component {

  state = {
    description: ''
  }

  constructor (props) => {
    const { description } = props;
    this.state = {description};
  }

  render () {
    const {state: { description }} = this;    
    return (
      <input type="text" value={description} />   
    );
  }
}

export default SecondComponent;

更新:setState()をthis.state = {}に変更しました(ジョーズ、ありがとう)。しかし、まだ違いはわかりません。他の1つより優れていますか?


10
なぜ小道具を州に保管しているのですか?値をキャッシュするのではなく、直接小道具を使用する必要があります。読んだReact.jsに国家としての小道具を設定する理由を冒涜されたgetInitialStateで小道具はアンチパターンです
Aurora0001

12
例-切り替え可能なコンポーネント(ポップオーバーやドロワーなど)。親は、コンポーネントを開いて開始するか閉じて開始するかを知っています。コンポーネント自体は、ある時点でそれが開いているかどうかを知ることができます。その場合、私this.state = { isVisible: props.isVisible }は理にかなっていると思います。アプリがUI状態をどのように配布するかによって異なります。
ジョーズ


5
2017年、Facebookは小道具を使用してドキュメントの初期状態を設定する方法を示しています:reactjs.org/docs/react-component.html#constructor
Rohmer

1
@ Aurora0001フォームを処理する必要がある状況で、それ自体がネットワークリクエストを作成する編集フォームで、そのコンポーネントのプロパティとして入力される値で入力を初期化する必要があるとします。フォームを動的に保つために、これらの値は状態を維持する必要があります。
Eric McWinNEr

回答:


196

状態に変化しないプロパティをコピーすることはアンチパターンであることに注意してください(その場合は、.propsに直接アクセスするだけです)。最終的に変化するが.propsからの値で始まる状態変数がある場合、コンストラクターを呼び出す必要さえありません。これらのローカル変数は、親のコンストラクターの呼び出し後に初期化されます。

class FirstComponent extends React.Component {
  state = {
    x: this.props.initialX,
    // You can even call functions and class methods:
    y: this.someMethod(this.props.initialY),
  };
}

これは、以下の@joewsからの回答に相当する省略表現です。es6トランスパイラーの最近のバージョンでのみ機能するようですが、一部のWebpackセットアップで問題が発生しました。これでうまくいかない場合は、babelプラグインを追加するbabel-plugin-transform-class-propertiesか、以下の@joewsで省略形以外のバージョンを使用できます。


1
あなたの答えが@joewsの答えとどのように異なるかをもっと説明できますか?
Jalal

3
「変数を設定するだけの場合は、コンストラクター呼び出しをスキップできます。」を追加しました。
Zane Hooper 2017

3
機能しない場合は、おそらくこのbabelプラグイン「babel-plugin-transform-class-properties」をインストールする必要があります。
Faheem

2
初期化後に状態が小道具に依存していないことが理解されている場合、小道具から状態を初期化することはアンチパターンではありません。2つを同期させようとする場合、それはアンチパターンです。
Yatrix

1
@ ak85それは同じ構文ですが、代わりにthis.stateを使用します。この構文は、クラス構築プロセス中に状態を設定するための簡単な構文です(状態以外の変数にも使用できます)
Zane Hooper

137

setStateコンポーネントの中で呼び出す必要はありませんconstructor- this.state直接設定するのは慣用的です:

class FirstComponent extends React.Component {

  constructor(props) {
    super(props);

    this.state = {
      x: props.initialX
    };
  }
  // ...
}

React docs-Local State to a Classを参照してください。

あなたが説明する最初の方法に利点はありません。これにより、コンポーネントを初めてマウントする直前に2回目の更新が行われます。


4
いい答えだ。これは初期状態を設定するためだけのものであることに注意してください。setStateそれ以外の時点で変更する場合は引き続き使用する必要があります。変更しないと、変更がレンダリングされない場合があります。
Aurora0001

おかげで再びjowes、二ドキュメンテーションfacebook.github.io/react/docs/...
レヴィ・モレイラ

(申し訳ありませんが、Enterキーを押します。.)より複雑なタスクでは、getInitialStateを使用して小道具を状態に設定する必要があります。単純な場合は、this.propsをレンダーに使用するだけですよね。
レヴィ・モレイラ

1
余談ですsuper(props)が、コンストラクタで使用してください。SOの議論
cutemachine

2
joewsの提案はほとんどの場合機能しますが、小道具をthis.stateに直接送信しないように注意してください。小道具をthis.stateにコピーすることは、実際には単一の真実のソースですmedium.com/react-ecosystem/…)。また、Dan Abramovはかつて、小道具の値を状態に保存しないことを提案しました。(twitter.com/dan_abramov/status/749710501916139520/photo/1)。
ヒロキ

33

代わりとして導入されたReact 16.3 alphaの更新static getDerivedStateFromProps(nextProps, prevState)ドキュメントcomponentWillReceiveProps

getDerivedStateFromPropsは、コンポーネントがインスタンス化された後、および新しいプロパティを受け取ったときに呼び出されます。状態を更新するオブジェクトを返すか、新しいプロップが状態の更新を必要としないことを示すnullを返します。

親コンポーネントによってコンポーネントが再レンダリングされる場合、小道具が変更されていなくても、このメソッドが呼び出されることに注意してください。変更のみを処理する場合は、新しい値と以前の値を比較することができます。

https://reactjs.org/docs/react-component.html#static-getderivedstatefromprops

それは静的である、したがって、それはへの直接アクセスを持っていないthis(それはへのアクセス権を持っているがprevState、通常に取り付けたもの格納することができた、this例えばrefs

コメントに@nerfologistの修正を反映するように編集


3
ただ、明確にするために、それが命名されますgetDerivedStateFromProps(小道具で大文字をマーク)とのparamsはnextPropsprevState(ないnextState):reactjs.org/docs/...
nerfologist

1
うわー!これを使用して、更新された小道具 を受け取ったときに状態を更新できます!
アロマルサシダーラン

2
getDerivedStateFromPropsが初期レンダリングの前に常に呼び出されることを考えると、コンストラクターで初期状態を作成する必要がありますか?
bvdb

19

すべての小道具を追加して同じ名前を保持したい場合は、以下のような短い形式を使用できます。

constructor(props) {
    super(props);
    this.state = {
       ...props
    }
    //...
}

1
状態に変化しないプロパティをコピーすることはアンチパターンです。コンポーネントが使用するフィールドを明示的に記述することをお勧めします。
Michael Freidgeim

5

このようにコンストラクタ内の状態データを設定します

constructor(props) {
    super(props);
    this.state = {
      productdatail: this.props.productdetailProps
    };
  }

プロップを介してサイドcomponentDidMount()メソッドでuを設定した場合、機能しません。




1

あなたはcomponentWillReceivePropsを使用することができます。

constructor(props) {
    super(props);
    this.state = {
      productdatail: ''
    };
  }

    componentWillReceiveProps(nextProps){
        this.setState({ productdatail: nextProps.productdetailProps })
    }

1
componentWillReceiveProps is Deprecated将来のバージョンでは使用できません
Vivek Ghanchi

1

コンストラクタでstatefrom を初期化するときは注意が必要ですprops場合であってもprops新しいものに変更マウントが再び起こることはありませんので、状態は変更されません。そのgetDerivedStateFromPropsために存在します。

class FirstComponent extends React.Component {
    state = {
        description: ""
    };

    static getDerivedStateFromProps(nextProps, prevState) {
        if (prevState.description !== nextProps.description) {
          return { description: nextProps.description };
        }

        return null;
    }

    render() {
        const {state: {description}} = this;    

        return (
            <input type="text" value={description} /> 
        );
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.