web-dev-qa-db-ja.com

ReactJSの状態配列の修正を修正しました

state配列の末尾に要素を追加したいのですが、これが正しい方法ですか?

this.state.arrayvar.Push(newelement);
this.setState({arrayvar:this.state.arrayvar});

Pushを使ってその場で配列を変更すると問題が起こる可能性があることを心配しています - 安全ですか?

配列のコピーを作成する代わりの方法、そしてそれは無駄に思われるsetStateing。

314
fadedbee

反応するドキュメント は言う:

これが不変であるかのようにthis.stateを扱います。

あなたのPushは直接状態を変化させるでしょう、そしてあなたがその後再び状態を "リセット"しているとしても、それは潜在的にエラーを起こしやすいコードに導くかもしれません。 F.ex、それはcomponentDidUpdateのようないくつかのライフサイクルメソッドがトリガーされないことにつながるかもしれません。

最近のReactバージョンで推奨されるアプローチは、競合状態を防ぐために状態を変更するときにupdater関数を使うことです。

this.setState(prevState => ({
  arrayvar: [...prevState.arrayvar, newelement]
}))

メモリの「無駄」は、標準以外の状態変更を使用した場合に発生する可能性があるエラーと比較して問題にはなりません。

以前のReactバージョンの代替構文

新しい配列を返すので、concatを使ってきれいな構文を得ることができます。

this.setState({ 
  arrayvar: this.state.arrayvar.concat([newelement])
})

ES6では、 スプレッド演算子 を使用できます。

this.setState({
  arrayvar: [...this.state.arrayvar, newelement]
})
611
David Hellsing

あなたがES6を使っているなら、最も簡単です。

initialArray = [1, 2, 3];

newArray = [ ...initialArray, 4 ]; // --> [1,2,3,4]

新しい配列は[1,2,3,4]になります

React で自分の状態を更新する

this.setState({arrayvar:[...this.state.arrayvar, newelement]});

配列のデストラクチャーについてもっと学びましょう

115
StateLess

ES6を使った最も簡単な方法:

this.setState(prevState => ({
    array: [...prevState.array, newElement]
}))
50
Ridd

Reactは更新をバッチ処理することがあるので、正しい方法は更新を実行する関数をsetStateに提供することです。

Reactアップデートアドオンの場合、次のものが確実に機能します。

this.setState( (state) => update(state, {array: {$Push: [4]}}) );

またはconcat()の場合:

this.setState( (state) => {
    state.array = state.array.concat([4]);
    return state;
});

以下は、間違った場合に何が起こるかの例として、 https://jsbin.com/mofekakuqi/7/edit?js,output を示しています。

ReactはsetTimeoutコールバック内でバッチ更新をバッチ処理しないため、setTimeout()呼び出しは3つの項目を正しく追加します( https://groups.google.com/d/msg/reactjs/G6pljvpTGX0/0ihYw2zK9dEJ を参照)。

OnClickのバグは "Third"を追加するだけですが、修正されたものは期待どおりにF、S、Tを追加します。

class List extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      array: []
    }

    setTimeout(this.addSome, 500);
  }

  addSome = () => {
      this.setState(
        update(this.state, {array: {$Push: ["First"]}}));
      this.setState(
        update(this.state, {array: {$Push: ["Second"]}}));
      this.setState(
        update(this.state, {array: {$Push: ["Third"]}}));
    };

  addSomeFixed = () => {
      this.setState( (state) => 
        update(state, {array: {$Push: ["F"]}}));
      this.setState( (state) => 
        update(state, {array: {$Push: ["S"]}}));
      this.setState( (state) => 
        update(state, {array: {$Push: ["T"]}}));
    };



  render() {

    const list = this.state.array.map((item, i) => {
      return <li key={i}>{item}</li>
    });
       console.log(this.state);

    return (
      <div className='list'>
        <button onClick={this.addSome}>add three</button>
        <button onClick={this.addSomeFixed}>add three (fixed)</button>
        <ul>
        {list}
        </ul>
      </div>
    );
  }
};


ReactDOM.render(<List />, document.getElementById('app'));
21
NealeU

@nilgunがコメントで述べたように、あなたはreact immutability helpers を使うことができます。私はこれがとても便利だと思った。

ドキュメントから:

シンプルプッシュ

var initialArray = [1, 2, 3];
var newArray = update(initialArray, {$Push: [4]}); // => [1, 2, 3, 4]

initialArrayはまだ[1、2、3]です。

17
Clarkie

このメソッドを使用することができます :[配列破壊]

this.setState(prevState => {
    return {
        arrayData: [...prevState.arrayData, newElement]
    }
});

React docs:this.stateを直接変更しないでください。 - David Hellsing 彼の答えで説明した:あとでsetState()を呼び出すと、行った変更が置き換えられる可能性があります。this.stateを不変のものとして扱うようにしてください。

1
Hsaidooo
this.setState({
  arrayvar: [...this.state.arrayvar, ...newelement]
})
0
M.Samiei