React:setStateを使用して状態のstate.item [1]を更新する方法?


259

ユーザーが自分のフォームをデザインできるアプリを作成しています。たとえば、フィールドの名前と、含まれる他の列の詳細を指定します。

このコンポーネントは、JSFiddleとしてここから入手できます

私の初期状態は次のようになります:

var DynamicForm = React.createClass({
  getInitialState: function() {
   var items = {};
   items[1] = { name: 'field 1', populate_at: 'web_start',
                same_as: 'customer_name',
                autocomplete_from: 'customer_name', title: '' };
   items[2] = { name: 'field 2', populate_at: 'web_end',
                same_as: 'user_name', 
                    autocomplete_from: 'user_name', title: '' };

     return { items };
   },

  render: function() {
     var _this = this;
     return (
       <div>
         { Object.keys(this.state.items).map(function (key) {
           var item = _this.state.items[key];
           return (
             <div>
               <PopulateAtCheckboxes this={this}
                 checked={item.populate_at} id={key} 
                   populate_at={data.populate_at} />
            </div>
            );
        }, this)}
        <button onClick={this.newFieldEntry}>Create a new field</button>
        <button onClick={this.saveAndContinue}>Save and Continue</button>
      </div>
    );
  }

ユーザーが値を変更したときに状態を更新したいのですが、正しいオブジェクトをターゲットにするのに苦労しています。

var PopulateAtCheckboxes = React.createClass({
  handleChange: function (e) {
     item = this.state.items[1];
     item.name = 'newName';
     items[1] = item;
     this.setState({items: items});
  },
  render: function() {
    var populateAtCheckbox = this.props.populate_at.map(function(value) {
      return (
        <label for={value}>
          <input type="radio" name={'populate_at'+this.props.id} value={value}
            onChange={this.handleChange} checked={this.props.checked == value}
            ref="populate-at"/>
          {value}
        </label>
      );
    }, this);
    return (
      <div className="populate-at-checkboxes">
        {populateAtCheckbox}
      </div>
    );
  }
});

this.setState更新するにはどうすればよいitems[1].nameですか?



1
この質問に対するあなたの選択した答えは何ですか?
Braian Mellor

回答:


126

updateこれに不変性ヘルパーを使用できます。

this.setState({
  items: update(this.state.items, {1: {name: {$set: 'updated field name'}}})
})

または、をshouldComponentUpdate()使用してライフサイクルメソッドでこのアイテムへの変更を検出できることを気にしない===場合は、状態を直接編集してコンポーネントを強制的に再レン​​ダリングすることができます。これは、@ limelightsの回答と実質的に同じです。オブジェクトを状態から引き出して編集する。

this.state.items[1].name = 'updated field name'
this.forceUpdate()

編集後の追加:

状態保持の親から状態変更をトリガーする必要がある子コンポーネントにコールバック関数を渡す方法の例については、反応トレーニングシンプルコンポーネント通信のレッスンをご覧ください。


125

このスレッドには多くの誤った情報があるため、ヘルパーライブラリなしでこれを行う方法を次に示します。

handleChange: function (e) {
    // 1. Make a shallow copy of the items
    let items = [...this.state.items];
    // 2. Make a shallow copy of the item you want to mutate
    let item = {...items[1]};
    // 3. Replace the property you're intested in
    item.name = 'newName';
    // 4. Put it back into our array. N.B. we *are* mutating the array here, but that's why we made a copy first
    items[1] = item;
    // 5. Set the state to our new copy
    this.setState({items});
},

必要に応じて、手順2と3を組み合わせることができます。

let item = {
    ...items[1],
    name: 'newName'
}

または、すべてを1行で実行できます。

this.setState(({items}) => ({
    items: [
        ...items.slice(0,1),
        {
            ...items[1],
            name: 'newName',
        },
        ...items.slice(2)
    ]
}));

注:items配列を作成しました。OPはオブジェクトを使用しました。ただし、概念は同じです。


あなたはあなたのターミナル/コンソールで何が起こっているのかを見ることができます:

 node
> items = [{name:'foo'},{name:'bar'},{name:'baz'}]
[ { name: 'foo' }, { name: 'bar' }, { name: 'baz' } ]
> clone = [...items]
[ { name: 'foo' }, { name: 'bar' }, { name: 'baz' } ]
> item1 = {...clone[1]}
{ name: 'bar' }
> item1.name = 'bacon'
'bacon'
> clone[1] = item1
{ name: 'bacon' }
> clone
[ { name: 'foo' }, { name: 'bacon' }, { name: 'baz' } ]
> items
[ { name: 'foo' }, { name: 'bar' }, { name: 'baz' } ] // good! we didn't mutate `items`
> items === clone
false // these are different objects
> items[0] === clone[0]
true // we don't need to clone items 0 and 2 because we're not mutating them (efficiency gains!)
> items[1] === clone[1]
false // this guy we copied

4
@TranslucentCloudああ、そうです、ヘルパーメソッドは間違いなく素晴らしいですが、私は誰もが
内部

なぜステップ2と3が必要なのですか?最初のステップの後でクローンを直接変異させることができないのはなぜですか?
Evmorov 2018

1
@Evmorovそれは深いクローンではないので。ステップ1は、アレイ内のオブジェクトではなく、アレイのクローンを作成するだけです。言い換えると、新しい配列内の各オブジェクトは依然としてメモリ内の既存のオブジェクトを「ポイント」しています。一方を変更すると、もう一方も変更されます(それらはまったく同じです)。items[0] === clone[0]下部の端末の例のビットも参照してください。=オブジェクトが同じものを参照しているかどうかをトリプルチェックします。
mpen 2018

配列内のアイテムのインデックスがわからない場合は、さらに複雑になります。
Ian Warburton

@IanWarburtonそうではありません。items.findIndex()その短い仕事をする必要があります。
mpen

92

進入禁止!

handleChange = (e) => {
    const { items } = this.state;
    items[1].name = e.target.value;

    // update state
    this.setState({
        items,
    });
};

多くの優れた開発者がコメントで指摘したように:状態の変更は間違っています!

これを理解するのにしばらくかかりました。上記は機能しますが、Reactの力を奪います。たとえば、componentDidUpdate直接変更されるため、これは更新とは見なされません。

したがって、正しい方法は次のとおりです。

handleChange = (e) => {
    this.setState(prevState => ({
        items: {
            ...prevState.items,
            [prevState.items[1].name]: e.target.value,
        },
    }));
};

25
ES6は「const」を使用しているだけの理由ですか?
nkkollaw

49
items[1].role = e.target.value変化状態を直接呼び出していませんか?
アントニー2017年

28
あなたは状態を変化させています、これはreactが提案するように状態を不変に維持するという考えに完全に反しています。これは、大きなアプリケーションで多くの苦痛を与える可能性があります。
ncubica

8
@MarvinVK、あなたの答えは「だからベストプラクティスは:」であり、その後に「this.forceUpdate();」を使用します。それがSETSTATE(によって上書きされる可能性があるのでお勧めしません)、参照facebook.github.io/react/docs/react-component.html#state。これを変更して、将来の読者を混乱させないようにすることをお勧めします。
James Z. 2017

8
多くのコメントは編集のために無関係であり、正しい方法は実際には正しい方法であることを指摘したかっただけです。
heez

50

リアクト状態に深くネストされたオブジェクト/変数を変更するには、一般的に3つの方法が使用されます。バニラはJavaScriptのObject.assign不変性ヘルパーcloneDeepからLodash

これを実現する他のあまり人気のないサードパーティのライブラリもたくさんありますが、この回答では、これら3つのオプションのみを取り上げます。また、配列の拡散など、追加のバニラJavaScriptメソッドがいくつか存在しますが(たとえば、@ mpenの回答を参照)、それらは非常に直感的でなく、使いやすく、すべての状態操作状況を処理できます。

回答へのトップ投票コメントで無数の時​​間が指摘されたように、その作者は状態の直接的な変異を提案していますただそれをしないでください。これはユビキタスなReactアンチパターンであり、必然的に望ましくない結果を招きます。正しい方法を学ぶ。

広く使用されている3つの方法を比較してみましょう。

この状態オブジェクト構造を考えると:

state = {
    outer: {
        inner: 'initial value'
    }
}

以下のメソッドを使用してinner、残りの状態に影響を与えることなく、最も内側のフィールドの値を更新できます。

1. Vanilla JavaScriptのObject.assign

const App = () => {
  const [outer, setOuter] = React.useState({ inner: 'initial value' })

  React.useEffect(() => {
    console.log('Before the shallow copying:', outer.inner) // initial value
    const newOuter = Object.assign({}, outer, { inner: 'updated value' })
    console.log('After the shallow copy is taken, the value in the state is still:', outer.inner) // initial value
    setOuter(newOuter)
  }, [])

  console.log('In render:', outer.inner)

  return (
    <section>Inner property: <i>{outer.inner}</i></section>
  )
}

ReactDOM.render(
  <App />,
  document.getElementById('react')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.10.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.10.2/umd/react-dom.production.min.js"></script>

<main id="react"></main>

Object.assign プロパティ値をコピーするだけなので、ディープクローニングを実行しないことに注意してください。このため、Object.assign が行うことは、浅いコピーと呼ばれます(コメントを参照)。

これが機能するためには、プリミティブ型(outer.inner)、つまり文字列、数値、ブール値のプロパティのみを操作する必要があります。

この例ではconst newOuter...、を使用して新しい定数()Object.assignを作成します。これにより、空のオブジェクト({})が作成され、outerオブジェクト({ inner: 'initial value' })がそのオブジェクトにコピーされ、その上に別のオブジェクトがコピーさ{ inner: 'updated value' } ます。

このようにして、最後に、新しく作成されたnewOuter定数は{ inner: 'updated value' }innerプロパティがオーバーライドされてからの値を保持します。これnewOuterは状態のオブジェクトにリンクされていない真新しいオブジェクトなので、必要に応じて変更することができ、状態を維持し、更新するコマンドが実行されるまで状態は変化しません。

最後の部分は、setOuter()setter を使用outerして状態の元のnewOuterオブジェクトを新しく作成されたオブジェクトに置き換えることです(値のみが変更され、プロパティ名outerは変更されません)。

ここで、のようなより深い状態があると想像してくださいstate = { outer: { inner: { innerMost: 'initial value' } } }newOuterオブジェクトを作成してouter、状態のコンテンツを設定Object.assignすることもできますが、ネストが深すぎるため、innerMostの値をこの新しく作成されたnewOuterオブジェクトにコピーできませんinnerMost

inner上記の例のように、引き続きをコピーすることもできますが、これはオブジェクトであり、プリミティブではないので、からの参照newOuter.innerouter.inner代わりにコピーされnewOuterます。つまり、状態のオブジェクトに直接関連付けられているローカルオブジェクトになります。

つまり、この場合、ローカルに作成された変更newOuter.innerouter.innerオブジェクト(状態)に直接影響します。なぜなら、それらは実際には同じもの(コンピューターのメモリ内)になっているためです。

Object.assign したがって、プリミティブ型の値を保持する最も内側のメンバーを持つ比較的単純な1レベルの深い状態構造がある場合にのみ機能します。

更新する必要があるより深いオブジェクト(第2レベル以上)がある場合は、を使用しないでくださいObject.assign。状態を直接変更するリスクがあります。

2. LodashのcloneDeep

const App = () => {
  const [outer, setOuter] = React.useState({ inner: 'initial value' })

  React.useEffect(() => {
    console.log('Before the deep cloning:', outer.inner) // initial value
    const newOuter = _.cloneDeep(outer) // cloneDeep() is coming from the Lodash lib
    newOuter.inner = 'updated value'
    console.log('After the deeply cloned object is modified, the value in the state is still:', outer.inner) // initial value
    setOuter(newOuter)
  }, [])

  console.log('In render:', outer.inner)

  return (
    <section>Inner property: <i>{outer.inner}</i></section>
  )
}

ReactDOM.render(
  <App />,
  document.getElementById('react')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.10.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.10.2/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>

<main id="react"></main>

LodashのcloneDeepの方がはるかに使いやすいです。これはディープクローニングを実行するので、内部にマルチレベルのオブジェクトまたは配列を持つかなり複雑な状態がある場合は、強力なオプションです。ただ、cloneDeep()トップレベルの状態の性質、あなたはどのような方法でクローン化された部分を変異させてください、そしてsetOuter()それがバック状態に。

3. 不変性ヘルパー

const App = () => {
  const [outer, setOuter] = React.useState({ inner: 'initial value' })
  
  React.useEffect(() => {
    const update = immutabilityHelper
    console.log('Before the deep cloning and updating:', outer.inner) // initial value
    const newOuter = update(outer, { inner: { $set: 'updated value' } })
    console.log('After the cloning and updating, the value in the state is still:', outer.inner) // initial value
    setOuter(newOuter)
  }, [])

  console.log('In render:', outer.inner)

  return (
    <section>Inner property: <i>{outer.inner}</i></section>
  )
}

ReactDOM.render(
  <App />,
  document.getElementById('react')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.10.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.10.2/umd/react-dom.production.min.js"></script>
<script src="https://wzrd.in/standalone/immutability-helper@3.0.0"></script>

<main id="react"></main>

immutability-helper全く新しいレベルにそれを取り、それについての涼しい事は、それができるだけでなく、ある$set状態の項目に値が、また$push$splice$merge(など)それら。以下は利用可能なコマンドのリストです。

サイドノート

ここでも、深くネストされた()ではなく、状態オブジェクトsetOuter第1レベルのプロパティのみを変更することに注意しouterてください(これらの例ではouter.inner)。別の方法で動作した場合、この質問は存在しません。

どちらがあなたのプロジェクトに適していますか?

外部の依存関係が不要または使用できず、単純な状態構造の場合は、に固執しObject.assignます。

巨大な状態や複雑な状態操作する場合cloneDeepは、Lodash が賢明な選択です。

高度な機能が必要場合、つまり状態構造が複雑で、あらゆる種類の操作を実行する必要がある場合は、を試してくださいimmutability-helper。これは、状態操作に使用できる非常に高度なツールです。

...または、本当にこれを行う必要がありますか?

Reactの状態で複雑なデータを保持している場合は、他の方法でデータを処理することを検討するのがよいでしょう。Reactコンポーネントで複雑な状態オブジェクトを正しく設定することは簡単な操作ではないので、さまざまなアプローチについて考えることを強くお勧めします。

おそらく、複雑なデータをReduxストアに保管し、レデューサーやsagasを使用してそこに設定し、セレクターを使用してアクセスすることをお勧めします。


Object.assignディープコピーを実行しません。たとえば、a = {c: {d: 1}}andのb = Object.assign({}, a)場合、を実行するとb.c.d = 4a.c.d変異します。
2017年

そうです1、最も内側のオブジェクト(a.c.d)の値が変化します。あなたが最初のレベルの後継再割り当てする場合はしかしb、このように、: b.c = {f: 1}、の対応する部分a変異し得ることはありませんが(それが滞在されます{d: 1})。とにかくいいキャッチ、私はすぐに答えを更新します。
神経伝達物質2017年

定義したのは、実際にはshallow copyであり、ではありませんdeep copy。何をshallow copy意味するのか混同しがちです。でshallow copya !== bが、ソースオブジェクトから各キーのためaa[key] === b[key]
AWOL

ええ、Object.assign答えで浅さを明示的に述べました。
神経伝達物質

JSON.parse(JSON.stringify(object))ディープクローンのバリアントでもあります。cloneDeepただし、パフォーマンスはlodashよりも劣ります。measurethat.net/Benchmarks/Show/2751/0/...
tylik

35

私も同じ問題を抱えていました。これが機能する簡単なソリューションです!

const newItems = [...this.state.items];
newItems[item] = value;
this.setState({ items:newItems });

11
@TranslucentCloud-これはおそらく直接的な変異ではありません。元のアレイが複製され、変更された後、複製された配列を使用して状態が再度設定されました。
vsync 2018

@vsyncええ、元の回答を編集した後、これはまったく突然変異ではありません。
神経伝達物質

2
@TranslucentCloud-以前にも、私の編集はそれとは何の関係もありませんでした。ここで@Jonasは、{私が
修正

31

setStateに関するReactのドキュメントによると、Object.assignここで他の回答で提案されているように使用することは理想的ではありません。setStateの非同期動作の性質上、この手法を使用した以降の呼び出しは、以前の呼び出しをオーバーライドして、望ましくない結果を引き起こす可能性があります。

代わりに、ReactのドキュメントsetStateでは、以前の状態で動作するアップデーター形式を使用することを推奨しています。Reactでは状態の不変性を維持する必要があるため、配列またはオブジェクト更新するときは、新しい配列またはオブジェクト返す必要があることに注意してください。ES6構文のスプレッド演算子を使用して配列を浅くコピーし、配列の特定のインデックスでオブジェクトのプロパティを作成または更新すると、次のようになります。

this.setState(prevState => {
    const newItems = [...prevState.items];
    newItems[index].name = newName;
    return {items: newItems};
})

2
ES6を使用する場合、これは適切な答えです。@Jonasの回答はインラインです。しかし説明のためにそれは際立っています。
Sourabh

はい、このコードは完全に正常に動作していると非常にシンプルなもの...
Shoebミルザ

29

まず、必要なアイテムを取得し、そのオブジェクトで必要なものを変更して、状態に戻します。getInitialStateキー付きオブジェクトを使用すると、オブジェクトを渡すだけで状態を使用する方法が簡単になります。

handleChange: function (e) {
   item = this.state.items[1];
   item.name = 'newName';
   items[1] = item;

   this.setState({items: items});
}

3
いや、それは降りますUncaught TypeError: Cannot read property 'items' of null
マーティン2015

いいえ、ありません。あなたのエラーはおそらくあなたがしている方法に起因しますgetInitialState
Henrik Andersson、

10
@HenrikAnderssonあなたの例では何かが正しくないようです。itemsどこにも定義されていません。
Edward D'Souza

1
@ EdwardD'Souza正解です!私の答えは、それがどのように定義され、使用されるべきかを示すことです。質問者のコードの設定方法は、彼/彼女が望むことに対して機能しないため、キー付きオブジェクトの必要性が要求されます。
Henrik Andersson 2016年

7
これは典型的なReactアンチパターンでありitem、状態自体のthis.state.items[1]変数への参照を割り当てます。次にitemitem.name = 'newName')を変更し、状態を直接変更します。これは推奨されません。あなたの例ではthis.setState({items: items})、状態はすでに直接変更されているため、を呼び出す必要すらありません。
神経伝達物質

22

状態を変更しないでください。予期しない結果を引き起こす可能性があります。レッスンを学びました!常にコピー/クローンで作業するのObject.assign()は良いことです:

item = Object.assign({}, this.state.items[1], {name: 'newName'});
items[1] = item;
this.setState({items: items});

https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign


8
itemsあなたの例には何がありますか?どういう意味this.state.itemsですか?
Bub Buh 2018

私はこれをテストしましたが、彼は1行欠落しています。上items[1] = item;には、と言う行があるはずitems = this.state.items;です。私のjavascriptは錆びていて、自分のホームプロジェクトへの反応を学んでいるので、これが良いか悪いか
わかり

4

とても簡単です。

まず、状態から項目オブジェクト全体をプルし、必要に応じて項目オブジェクトの一部を更新し、setStateを介して項目オブジェクト全体を状態に戻します。

handleChange: function (e) {
  items = Object.assign(this.state.items); // Pull the entire items object out. Using object.assign is a good idea for objects.
  items[1].name = 'newName'; // update the items object as needed
  this.setState({ items }); // Put back in state
}

「Object.assignは、プリミティブ型の値を保持する最も内側のメンバーを持つ比較的単純な1レベルの深い状態構造がある場合に機能します。」
神経伝達物質

3

上記のオプションのどれも私にとって理想的ではなかったので、私は最終的にマップを使用しました:

this.setState({items: this.state.items.map((item,idx)=> idx!==1 ?item :{...item,name:'new_name'}) })

2

無突然変異:

// given a state
state = {items: [{name: 'Fred', value: 1}, {name: 'Wilma', value: 2}]}

// This will work without mutation as it clones the modified item in the map:
this.state.items
   .map(item => item.name === 'Fred' ? {...item, ...{value: 3}} : item)

this.setState(newItems)

2
どこnewItemsが設定されているのかわかりません。
神経伝達物質

配列内のマップと比較はパフォーマンスにとって恐ろしいものではありませんか?
Natassia Tavares、2018

@NatassiaTavares ..何ですか?多分あなたは混乱しているfo ofか、forEachマップが最速です。
Deano

1

これは驚くほど困難で、ES6スプレッドマジックは期待どおりに動作しないようでした。このような構造を使用して、レイアウト目的でレンダリングされた要素のプロパティを取得していました。

updateメソッドfrom immutability-helperを使用して、この単純化された例で最も単純なものであることがわかりました

constructor(props) {
    super(props)
    this.state = { values: [] }
    this.updateContainerState = this.updateContainerState.bind(this)
  }

updateContainerState(index, value) {
    this.setState((state) => update(state, { values: { [index]: { $set: value } } }))
  }

https://github.com/kolodny/immutability-helper#computed-property-namesから変更

更新される配列メンバーのより入れ子になった複雑なオブジェクトは、複雑さに基づいて適切なディープコピーメソッドを使用します。

レイアウトパラメータを処理する方法は確かに優れていますが、これは配列の処理方法です。各子要素の関連する値もそれらの外部で計算することもできますが、containerStateを渡すと、子がプロパティを自由にフェッチし、指定されたインデックスで親の状態配列を更新できるので便利です。

import React from 'react'
import update from 'immutability-helper'
import { ContainerElement } from './container.component.style.js'
import ChildComponent from './child-component'
export default class ContainerComponent extends React.Component {
  constructor(props) {
    super(props)
    this.state = { values: [] }
    this.updateContainerState = this.updateContainerState.bind(this)
  }

  updateContainerState(index, value) {
    this.setState((state) => update(state, { values: { [index]: { $set: value } } }))
  }

  // ...

  render() {
    let index = 0
    return (
      <ContainerElement>
      <ChildComponent
        index={index++}
        containerState={this.state}
        updateContainerState={this.updateContainerState}
      />
      <ChildComponent
        index={index++}
        containerState={this.state}
        updateContainerState={this.updateContainerState}
      />
      </ContainerElement>
    )
  }
}



0

関数ハンドルの変更を移動してインデックスパラメータを追加します

handleChange: function (index) {
    var items = this.state.items;
    items[index].name = 'newName';
    this.setState({items: items});
},

動的フォームコンポーネントに追加し、それをPopulateAtCheckboxesコンポーネントにプロップとして渡します。アイテムをループするときに、次のようにハンドルの変更に渡される追加のカウンター(以下のコードではインデックスと呼ばれます)を含めることができます

{ Object.keys(this.state.items).map(function (key, index) {
var item = _this.state.items[key];
var boundHandleChange = _this.handleChange.bind(_this, index);
  return (
    <div>
        <PopulateAtCheckboxes this={this}
            checked={item.populate_at} id={key} 
            handleChange={boundHandleChange}
            populate_at={data.populate_at} />
    </div>
);
}, this)}

最後に、以下に示すように変更リスナーを呼び出すことができます

<input type="radio" name={'populate_at'+this.props.id} value={value} onChange={this.props.handleChange} checked={this.props.checked == value} ref="populate-at"/>

Reactの状態を直接変更しないでください。
神経伝達物質

0

の一部のみを変更する必要がある場合はArray、ステートが設定された反応コンポーネントがあります。

state = {items: [{name: 'red-one', value: 100}, {name: 'green-one', value: 999}]}

これは、更新するのが最善ですred-oneArray次のように:

const itemIndex = this.state.items.findIndex(i=> i.name === 'red-one');
const newItems = [
   this.state.items.slice(0, itemIndex),
   {name: 'red-one', value: 666},
   this.state.items.slice(itemIndex)
]

this.setState(newItems)

なにnewArray?どういう意味newItems?もしそうなら、それは後に1つのアイテムだけで状態を残しませんか?
micnil 2017年

これnewItemsにより、stateオブジェクトに新しいプロパティが導入され、既存のitemsプロパティは更新されません。
神経伝達物質

0

または、動的に生成されたリストがあり、インデックスがわからないが、キーまたはIDがある場合:

let ItemsCopy = []
let x = this.state.Items.map((entry) =>{

    if(entry.id == 'theIDYoureLookingFor')
    {
        entry.PropertyToChange = 'NewProperty'
    }

    ItemsCopy.push(entry)
})


this.setState({Items:ItemsCopy});

0

コードで試してください:

this.state.items[1] = 'new value';
var cloneObj = Object.assign({}, this.state.items);

this.setState({items: cloneObj });

0

次のコードは私の鈍い脳に簡単に行きました。オブジェクトを削除し、更新されたオブジェクトで置き換える

    var udpateditem = this.state.items.find(function(item) { 
                   return item.name == "field_1" });
    udpateditem.name= "New updated name"                       
    this.setState(prevState => ({                                   
    items:prevState.dl_name_template.filter(function(item) { 
                                    return item.name !== "field_1"}).concat(udpateditem)
    }));

0

別のコンポーネント(配列に入れる必要のあるオブジェクト用)を作成して、以下を小道具として渡しますか?

  1. コンポーネントインデックス-インデックスは、配列の作成/更新に使用されます。
  2. set関数-この関数は、コンポーネントのインデックスに基づいてデータを配列に入れます。
<SubObjectForm setData={this.setSubObjectData}                                                            objectIndex={index}/>

ここで、{index}は、このSubObjectFormが使用される位置に基づいて渡す​​ことができます。

そして、setSubObjectDataはこのようなものにすることができます。

 setSubObjectData: function(index, data){
      var arrayFromParentObject= <retrieve from props or state>;
      var objectInArray= arrayFromParentObject.array[index];
      arrayFromParentObject.array[index] = Object.assign(objectInArray, data);
 }

SubObjectFormでは、this.props.setDataは、以下に示すようにデータ変更時に呼び出すことができます。

<input type="text" name="name" onChange={(e) => this.props.setData(this.props.objectIndex,{name: e.target.value})}/>

0
this.setState({
      items: this.state.items.map((item,index) => {
        if (index === 1) {
          item.name = 'newName';
        }
        return item;
      })
    });

1
これは最適ではないので、2番目の項目のみを更新するために配列全体を反復しますか?
wscourge

最初の配列の要素も変更するので、使用する必要がありますitem = Object.assign({}, item, {name: 'newName'});
remram

0

@JonnyBuchananの答えは完全に機能しますが、配列状態変数に対してのみです。状態変数が1つの辞書にすぎない場合は、次のようにします。

inputChange = input => e => {
    this.setState({
        item: update(this.state.item, {[input]: {$set: e.target.value}})
    })
}

[input]辞書のフィールド名とe.target.valueその値で置き換えることができます。このコードは、フォームの入力変更イベントで更新ジョブを実行します。


-3

これを試してみれば確実に機能しますが、他のケースでは試しても機能しませんでした

import _ from 'lodash';

this.state.var_name  = _.assign(this.state.var_name, {
   obj_prop: 'changed_value',
});

Reactの状態を直接変更しないでください。
神経伝達物質2017年

-3
 handleChanges = (value, key) => {
     // clone the current State object
    let cloneObject = _.extend({}, this.state.currentAttribute);
    // key as user.name and value= "ABC" then current attributes have current properties as we changes
    currentAttribute[key] = value;
    // then set the state "currentAttribute" is key and "cloneObject" is changed object.  
    this.setState({currentAttribute: cloneObject});

テキストボックスからの変更とonChangeイベントを追加

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