Reactでネストされた状態プロパティを更新する方法


390

次のようにネストされたプロパティを使用して自分の状態を整理しようとしています:

this.state = {
   someProperty: {
      flag:true
   }
}

しかし、このように状態を更新すると、

this.setState({ someProperty.flag: false });

動作しません。これをどのように正しく行うことができますか?


4
どういう意味ですか?これはあまり良い質問ではありません-何が起こりましたか?エラーはありますか?どんなエラー?
Darren Sweeney 2017年


16
答えは、ReactでNested Stateを使用しないくださいこの優れた答えを読んでください。
Qwerty、2018

4
代わりに何を使用する必要がありますか?
ジャニスElmeris

42
ネストされた状態を単に使用しないことは、Reactが今日どのように広く使用されているかについて、受け入れがたい答えです。この状況が発生し、開発者はこれに対する答えが必要です。
serraosays

回答:


456

するために、setState私はSETSTATEは、ネストされた更新を処理しないと思うと、ネストされたオブジェクトのためのあなたは、以下のアプローチに従うことができます。

var someProperty = {...this.state.someProperty}
someProperty.flag = true;
this.setState({someProperty})

アイデアは、ダミーオブジェクトを作成して操作を実行し、コンポーネントの状態を更新されたオブジェクトで置き換えることです。

これで、spreadオペレーターは、オブジェクトの1レベルのネストされたコピーのみを作成します。状態が次のように高度にネストされている場合:

this.state = {
   someProperty: {
      someOtherProperty: {
          anotherProperty: {
             flag: true
          }
          ..
      }
      ...
   }
   ...
}

あなたはのような各レベルでスプレッド演算子を使用してsetStateをすることができます

this.setState(prevState => ({
    ...prevState,
    someProperty: {
        ...prevState.someProperty,
        someOtherProperty: {
            ...prevState.someProperty.someOtherProperty, 
            anotherProperty: {
               ...prevState.someProperty.someOtherProperty.anotherProperty,
               flag: false
            }
        }
    }
}))

ただし、上記の構文は状態が次第にネストされるにつれて醜くなりますimmutability-helper。そのため、パッケージを使用して状態を更新することをお勧めします。

で状態を更新する方法については、この回答を参照してくださいimmutability helper


2
@Ohgodwhy、いいえ、{... this.state.someProperty}が新しいオブジェクトを返却しsomeProperty、これを変更しているため、これは状態に直接アクセスしていません
Shubham Khatri

4
これは私にとってはうまくいきませんでした..私は反応バージョン@ 15.6.1を使用しています
Rajiv

5
@Stophface Lodashを使用して確実にディープクローンを作成できますが、setStateのためだけにこのライブラリを含めるとは限りません
Shubham Khatri

15
これはreactjs.org/docs/…に違反していませんか?ネストされたオブジェクトに対する2つの変更がバッチ処理された場合、最後の変更によって最初の変更が上書きされます。したがって、最も正しい方法は次のようになります。this.setState((prevState) => ({nested: {...prevState.nested, propertyToSet: newValue}}) 少し面倒ですが
olejorgenb

2
私はあなたが必要とは思わない...prevState,、あなただけの最後の例ではsomeProperty、その子供たち
Jemarジョーンズ

140

一行で書くには

this.setState({ someProperty: { ...this.state.someProperty, flag: false} });

12
setState内でthis.stateに直接アクセスするのではなく、setStateのアップデーターを使用することをお勧めします。reactjs.org/docs/react-component.html#setstate
Raghu Teja

6
私はそれが言っていると信じています、this.stateすぐに読んsetStateで、それが新しい価値を持っていると期待しないでください。this.state内での呼び出しとの比較setState。または、私には明確ではない後者の問題もありますか?
trpt4him

2
以下のようtrpt4himは言った、リンクはあなたはアクセスの問題について話し合いましたthis.state後にsetState。その上、私たちはに渡っthis.stateていませんsetStateオペレータ拡がり性。Object.assign()と同じです。github.com/tc39/proposal-object-rest-spread
Yoseph

3
@RaghuTejaだけでthis.setState(currentState => { someProperty: { ...currentState.someProperty, flag: false} });この問題を回避できるかもしれません か?
Webwoman

完全を期すために、useStateフックで同じことを実現する方法の答えを追加しまし
Andrew

90

時々、直接的な答えは最良のものではありません:)

短縮版:

このコード

this.state = {
    someProperty: {
        flag: true
    }
}

のように簡略化する必要があります

this.state = {
    somePropertyFlag: true
}

ロングバージョン:

現在のところ、Reactでネストされた状態を操作する必要はありません。Reactはネストされた状態で動作するように指向されておらず、ここで提案されるすべてのソリューションはハックのように見えるためです。彼らはフレームワークを使用しませんが、それと戦います。彼らはいくつかのプロパティをグループ化するという疑わしい目的のためにそれほど明確でないコードを書くことを提案します。したがって、これらは挑戦への回答として非常に興味深いですが、実際には役に立ちません。

次の状態を想像してみましょう:

{
    parent: {
        child1: 'value 1',
        child2: 'value 2',
        ...
        child100: 'value 100'
    }
}

の値だけを変更するとどうなりますchild1か?浅い比較を使用しているため、Reactはビューを再レンダリングparentしません。また、プロパティは変更されていません。ちなみに、状態オブジェクトを直接変更することは、一般に悪い習慣と見なされています。

したがって、全体を再作成する必要があります parentオブジェクトます。しかし、この場合、別の問題が発生します。Reactは、すべての子供が値を変更したと考え、それらすべてを再レンダリングします。もちろん性能は良くありません。

いくつかの複雑なロジックを記述することでその問題を解決することはまだ可能shouldComponentUpdate()ですが、ここで止めて、短いバージョンの簡単な解決策を使用したいと思います。


4
入れ子の状態が完全に良いユースケースがあると思います。たとえば、キーと値のペアを動的に追跡する状態。あなたの状態で1つだけのエントリの状態を更新することができますどのようにここを参照してください:reactjs.org/docs/...
PORS

1
純粋なコンポーネントには、デフォルトで浅い比較が使用されます。
バーゼルシシャニ2018

4
敬意を表して祭壇を作り、毎朝お祈りしたいと思います。この答えにたどり着くのに3日かかりました。ネストされた状態がより人間が読めるように見えるからといって、誰もがスプレッド演算子を使用したり、他のハックを試みたりするだけです。
エデフ2018年

1
では、Reactを使用してインタラクティブツリーのレンダリングなどを行うにはどうすればよいでしょうか(たとえば、私の会社では、世界のさまざまな場所に、さまざまなタイプのさまざまなプロパティのさまざまな場所にセンサーの束があります(80以上)、そしてもちろん、各展開には数千ドルの費用がかかり、完全なプロジェクトであるため、階層なしでそれらを管理することは不可能であるため、それらは階層的に編成されています)。私は、Reactで、木のようなものを...木のようにモデル化しないことにかなり興味があります。
DanyAlejandro

10
Reactは、重要な深さの再帰的な構造として格納されているものを表すために作られたものではないようです。そこにあるほとんどすべての複雑なアプリケーション(Gmail、ファイルマネージャー、任意のドキュメント管理システムなど)にツリービューが表示されるので、少しがっかりします。私はこれらのことのためにReactを使用しましたが、常にアンチパターンを実行していることを全員に伝え、ソリューションがすべてのノードの状態でツリーの深いコピーを保持することを提案するReactの熱意を持っていました(はい、80コピー)。Reactのルールに違反しない、ハックのないツリービューコンポーネントが欲しいです。
DanyAlejandro

62

免責事項

Reactのネストされた状態は間違った設計です

この優れた答えを読んでください。

 

この回答の理由:

ReactのsetStateは組み込みの便利さですが、すぐに制限があることに気付くでしょう。カスタムプロパティを使用し、forceUpdateをインテリジェントに使用すると、さらに多くのことが可能になります。例えば:

class MyClass extends React.Component {
    myState = someObject
    inputValue = 42
...

たとえば、MobXは状態を完全に切り離し、カスタムの監視可能なプロパティを使用します。
Reactコンポーネントで状態の代わりにオブザーバブルを使用します。

 


あなたの悲惨さに対する答え- ここの例を見てください

ネストされたプロパティを更新する別の短い方法があります。

this.setState(state => {
  state.nested.flag = false
  state.another.deep.prop = true
  return state
})

一行に

 this.setState(state => (state.nested.flag = false, state))

注:これはコンマ演算子〜MDNです。実際の動作はこちら(サンドボックス)を参照してください。

(これは状態参照を変更しませんが)に似ています

this.state.nested.flag = false
this.forceUpdate()

このコンテキストの微妙な違いについては、リンクされた例forceUpdatesetState参照してください。

もちろん、これはいくつかの中核的な原則を乱用しています。 state読み取り専用で必要があるためていますが、古い状態をすぐに破棄して新しい状態に置き換えるため、完全に問題ありません。

警告

状態含むコンポーネントは適切に更新および再レンダリングされますがこの落とし穴を除く、プロップは子への伝播に失敗ます(下記のSpymasterのコメントを参照)。この手法は、自分が何をしているのかわかっている場合にのみ使用してください。

たとえば、更新されて簡単に渡される、変更されたフラットプロップを渡すことができます。

render(
  //some complex render with your nested state
  <ChildComponent complexNestedProp={this.state.nested} pleaseRerender={Math.random()}/>
)

これで、complexNestedPropの参照は変更されませんでした(shouldComponentUpdate

this.props.complexNestedProp === nextProps.complexNestedProp

コンポーネント、親コンポーネントが更新されるたびに再レンダリングされます。これは、呼び出し後this.setStateまたはthis.forceUpdate親で行われます。

状態の変化の影響

ネストされた状態を使用し、状態を直接変更することは危険です。異なるオブジェクトが状態への異なる(古い)参照を(意図的に、または意図せずに)保持し、いつ更新するかを必ずしも知っていない可能性があるためです(たとえば、使用PureComponentする場合、またはshouldComponentUpdate返されるように実装されている場合falseORは以下の例のように古いデータを表示するためのものです。

履歴データをレンダリングすることになっているタイムラインを想像してください。手元のデータを変更すると、以前のアイテムも変更されるため、予期しない動作が発生します。

状態フロー 状態フローのネスト

とにかく、ここNested PureChildClassでは、プロップが伝播に失敗したために再レンダリングされていないことがわかります。


12
どこでも反応状態を変更するべきではありません。state.nestedまたはstate.anotherからのデータを使用するネストされたコンポーネントがある場合、それらは再レンダリングされず、子もレンダリングされません。これはオブジェクトが変更されなかったため、Reactは何も変更されていないと考えています。
Zeragamba、

@ SpyMaster356私はこれに対処するために私の答えを更新しました。たとえば、MobXはstate完全に切り離され、カスタムの監視可能なプロパティを使用することにも注意してください。React setStateは組み込みの便利さですが、すぐに制限があることに気付くでしょう。カスタムプロパティを使用してインテリジェントに使用すると、forceUpdateさらに多くのことが可能になります。Reactコンポーネントで状態の代わりにオブザーバブルを使用します。
Qwerty、2018

また、react-experiments.herokuapp.com / state-flowの例を追加しました(上部のgitへのリンク)
Qwerty

たとえば、ネストされた属性を持つオブジェクトをデータベースから状態にロードするとどうなりますか?その場合にネストされた状態を回避するにはどうすればよいですか?
tobiv

3
@tobivフェッチ時にデータを別の構造に変換することをお勧めしますが、ユースケースによって異なります。ネストされたオブジェクトまたはオブジェクトの配列を、あるデータのコンパクトな単位と考える場合は、ある状態で問題ありません。この問題は、UIのスイッチやその他の監視可能なデータ(つまり、ビューをすぐに変更する必要のあるデータ)を格納する必要がある場合に発生します。他のネストされたオブジェクトの変更については、this.forceUpdate()特定のをトリガーまたは実装するのは簡単shouldComponentUpdateです。
Qwerty

21

ES2015を使用している場合は、Object.assignにアクセスできます。次のように使用して、ネストされたオブジェクトを更新できます。

this.setState({
  someProperty: Object.assign({}, this.state.someProperty, {flag: false})
});

更新されたプロパティを既存のプロパティとマージし、返されたオブジェクトを使用して状態を更新します。

編集:空のオブジェクトをターゲットとして割り当て関数に追加し、carkodが指摘したように、状態が直接変更されないようにしました。


12
そして私は間違っているかもしれませんが、ES2015 なしで React 使用しているとは思いません。
Madbreaks 2017年

16
const newState = Object.assign({}, this.state);
newState.property.nestedProperty = "new value";
this.setState(newState);

1
ここではよりエレガントな解決策のようです、1)setState内の面倒な拡散を回避し、2)setState内に新しい状態をうまく配置し、setState内の直接の変更を回避します。最後に
重要

2つの例は同等ではありません。propertyに複数のネストされたプロパティが含まれている場合、最初のプロパティはそれらを削除し、2番目のプロパティは削除しません。codesandbox.io/s/nameless-pine-42thu
Qwerty

Qwerty、あなたは正しい、努力をありがとう。ES6バージョンを削除しました。
eyecandy.dev

シンプルでシンプル!
トニーセピア

私はあなたの解決策を使いました。私の状態オブジェクトは小さく、うまくいきました。Reactは変更された状態のみをレンダリングしますか、それともすべてをレンダリングしますか?
野口健二

14

これに役立つライブラリがたくさんあります。たとえば、immutability-helperを使用します。

import update from 'immutability-helper';

const newState = update(this.state, {
  someProperty: {flag: {$set: false}},
};
this.setState(newState);

lodash / fpセットの使用:

import {set} from 'lodash/fp';

const newState = set(["someProperty", "flag"], false, this.state);

lodash / fpマージの使用:

import {merge} from 'lodash/fp';

const newState = merge(this.state, {
  someProperty: {flag: false},
});

を使用する場合はlodash_.cloneDeep状態を複製したコピーにしてみてください。
Liu

@YixingLiu:使用するlodash/fpように回答を更新したので、突然変異を心配する必要はありません。
tokland 2018

構文以外にlodash / fpで選択mergeまたはset機能する利点はありますか?
ToivoSäwén

良い答えですthis.setState(newState)。lodash/ fpメソッドも呼び出す必要があることを追加したいと思うかもしれません。もう1つの問題は、lodash .set(非fp)が異なる順序の引数を持っていることです。
ToivoSäwén

7

これらの種類の問題を処理するには、Immer https://github.com/mweststrate/immerを使用します。

コンポーネントの1つでこのコードを置き換えただけです

this.setState(prevState => ({
   ...prevState,
        preferences: {
            ...prevState.preferences,
            [key]: newValue
        }
}));

これとともに

import produce from 'immer';

this.setState(produce(draft => {
    draft.preferences[key] = newValue;
}));

イマーを使用すると、状態を「通常のオブジェクト」として扱います。魔法は、プロキシオブジェクトを使用して舞台裏で起こります。


6

これは、追加のパッケージ、ライブラリ、または特別な関数を必要としない、このスレッドで与えられた最初の回答のバリエーションです。

state = {
  someProperty: {
    flag: 'string'
  }
}

handleChange = (value) => {
  const newState = {...this.state.someProperty, flag: value}
  this.setState({ someProperty: newState })
}

特定のネストされたフィールドの状態を設定するために、オブジェクト全体を設定しました。これを行うには、変数を作成し、最初にES2015 スプレッドオペレーターを使用newStateして、現在の状態の内容を変数に展開しました。次に、の値を新しい値に置き換えました(現在の状態をオブジェクトに展開した後で設定しため、現在の状態のフィールドはオーバーライドされます)。その後、私は単にの状態を設定し、私にオブジェクト。this.state.flagflag: value flagsomePropertynewState


6

ネストは実際にはコンポーネントの状態を処理する方法ではありませんが、単一層のネストが簡単な場合もあります。

このような状態の場合

state = {
 contact: {
  phone: '888-888-8888',
  email: 'test@test.com'
 }
 address: {
  street:''
 },
 occupation: {
 }
}

使用される再利用可能なメソッドは次のようになります。

handleChange = (obj) => e => {
  let x = this.state[obj];
  x[e.target.name] = e.target.value;
  this.setState({ [obj]: x });
};

次に、アドレス指定する各ネストのobj名を渡します...

<TextField
 name="street"
 onChange={handleChange('address')}
 />

4

このソリューションを使用しました。

次のようなネストされた状態がある場合:

   this.state = {
          formInputs:{
            friendName:{
              value:'',
              isValid:false,
              errorMsg:''
            },
            friendEmail:{
              value:'',
              isValid:false,
              errorMsg:''
            }
}

現在のステータスをコピーし、変更された値で再割り当てするhandleChange関数を宣言できます

handleChange(el) {
    let inputName = el.target.name;
    let inputValue = el.target.value;

    let statusCopy = Object.assign({}, this.state);
    statusCopy.formInputs[inputName].value = inputValue;

    this.setState(statusCopy);
  }

ここにイベントリスナーを含むhtml

<input type="text" onChange={this.handleChange} " name="friendName" />

確認しました。これは、ネストされたプロパティを持つすでに確立されたプロジェクトをすでに扱っている場合に最適です。
metal_jacke1

4

状態のコピーを作成します。

let someProperty = JSON.parse(JSON.stringify(this.state.someProperty))

このオブジェクトを変更します。

someProperty.flag = "false"

状態を更新してください

this.setState({someProperty})

setStateは非同期です。そのため、更新中に他の誰かがこの関数を呼び出して、古いバージョンの状態をコピーできます。
Aviv Ben Shabat

3

クラスベースのReactコンポーネントの状態について尋ねましたが、useStateフックにも同じ問題が存在します。さらに悪いことに、useStateフックは部分的な更新を受け入れません。そのため、useStateフックが導入されたときに、この質問は非常に関連性が高くなりました。

次の回答を投稿して、useStateフックが使用されるより現代的なシナリオを質問に確実にカバーすることにしました。

あなたが持っている場合:

const [state, setState] = useState({ someProperty: { flag: true, otherNestedProp: 1 }, otherProp: 2 })

現在のクローンを作成し、データの必要なセグメントにパッチを適用することで、ネストされたプロパティを設定できます。次に例を示します。

setState(current => { ...current, someProperty: { ...current.someProperty, flag: false } });

または、Immerライブラリを使用して、オブジェクトのクローニングとパッチ適用を簡略化できます。

または、Hookstateライブラリ(免責事項:私は作成者です)を使用して、複雑な(ローカルおよびグローバル)状態データを完全に管理し、パフォーマンスを向上させることができます(読み取り:レンダリングの最適化について心配する必要はありません)。

import { useStateLink } from '@hookstate/core' 
const state = useStateLink({ someProperty: { flag: true, otherNestedProp: 1 }, otherProp: 2 })

レンダリングするフィールドを取得します。

state.nested.someProperty.nested.flag.get()
// or 
state.get().someProperty.flag

ネストされたフィールドを設定します。

state.nested.someProperty.nested.flag.set(false)

これはフックステートの例です。ここでは、状態はツリーのようなデータ構造に深く/再帰的にネストされています


2

まだ言及されていない他の2つのオプション:

  1. 入れ子の状態が深い場合は、子オブジェクトを再構築してルートに配置できるかどうかを検討してください。これにより、データの更新が容易になります。
  2. 不変の状態を処理するために利用できる多くの便利なライブラリがあります Reduxのドキュメントに記載されている。変更可能な方法でコードを記述できるが、必要な複製を舞台裏で処理するため、Immerをお勧めします。また、結果のオブジェクトをフリーズするため、後で誤って変更することもありません。

2

一般的なものにするために、@ ShubhamKhatriと@Qwertyの回答に取り組みました。

状態オブジェクト

this.state = {
  name: '',
  grandParent: {
    parent1: {
      child: ''
    },
    parent2: {
      child: ''
    }
  }
};

入力コントロール

<input
  value={this.state.name}
  onChange={this.updateState}
  type="text"
  name="name"
/>
<input
  value={this.state.grandParent.parent1.child}
  onChange={this.updateState}
  type="text"
  name="grandParent.parent1.child"
/>
<input
  value={this.state.grandParent.parent2.child}
  onChange={this.updateState}
  type="text"
  name="grandParent.parent2.child"
/>

updateStateメソッド

@ShubhamKhatriの回答としてのsetState

updateState(event) {
  const path = event.target.name.split('.');
  const depth = path.length;
  const oldstate = this.state;
  const newstate = { ...oldstate };
  let newStateLevel = newstate;
  let oldStateLevel = oldstate;

  for (let i = 0; i < depth; i += 1) {
    if (i === depth - 1) {
      newStateLevel[path[i]] = event.target.value;
    } else {
      newStateLevel[path[i]] = { ...oldStateLevel[path[i]] };
      oldStateLevel = oldStateLevel[path[i]];
      newStateLevel = newStateLevel[path[i]];
    }
  }
  this.setState(newstate);
}

@Qwertyの回答としてのsetState

updateState(event) {
  const path = event.target.name.split('.');
  const depth = path.length;
  const state = { ...this.state };
  let ref = state;
  for (let i = 0; i < depth; i += 1) {
    if (i === depth - 1) {
      ref[path[i]] = event.target.value;
    } else {
      ref = ref[path[i]];
    }
  }
  this.setState(state);
}

注:上記のメソッドは配列では機能しません


2

私は、コンポーネントの状態の完全なコピーを作成することに関してすでに述べられている懸念を非常に真剣に受け止めてます。そうは言っても、私はイマーを強くお勧めします。

import produce from 'immer';

<Input
  value={this.state.form.username}
  onChange={e => produce(this.state, s => { s.form.username = e.target.value }) } />

プロキシオブジェクトを巧みに使用して任意の深さの状態ツリーを効率的にコピーするため、これは機能しますReact.PureComponent(つまり、Reactによる浅い状態の比較)Immer。Immerは、Immutability Helperなどのライブラリと比較してタイプセーフでもあり、JavascriptとTypescriptのユーザーにとって理想的です。


Typescriptユーティリティ関数

function setStateDeep<S>(comp: React.Component<any, S, any>, fn: (s: 
Draft<Readonly<S>>) => any) {
  comp.setState(produce(comp.state, s => { fn(s); }))
}

onChange={e => setStateDeep(this, s => s.form.username = e.target.value)}

1
stateUpdate = () => {
    let obj = this.state;
    if(this.props.v12_data.values.email) {
      obj.obj_v12.Customer.EmailAddress = this.props.v12_data.values.email
    }
    this.setState(obj)
}

1
これは正しい状態だとは思いません。これはobj単なる状態への参照なので、実際のthis.stateオブジェクトを
変化

0

これは私にとってはうまくいくことがわかりました。私の場合、たとえば、IDと名前があり、ネストされたプロジェクトの状態を維持したいプロジェクトフォームがあります。

return (
  <div>
      <h2>Project Details</h2>
      <form>
        <Input label="ID" group type="number" value={this.state.project.id} onChange={(event) => this.setState({ project: {...this.state.project, id: event.target.value}})} />
        <Input label="Name" group type="text" value={this.state.project.name} onChange={(event) => this.setState({ project: {...this.state.project, name: event.target.value}})} />
      </form> 
  </div>
)

お知らせ下さい!


0

このような何かで十分かもしれません、

const isObject = (thing) => {
    if(thing && 
        typeof thing === 'object' &&
        typeof thing !== null
        && !(Array.isArray(thing))
    ){
        return true;
    }
    return false;
}

/*
  Call with an array containing the path to the property you want to access
  And the current component/redux state.

  For example if we want to update `hello` within the following obj
  const obj = {
     somePrimitive:false,
     someNestedObj:{
        hello:1
     }
  }

  we would do :
  //clone the object
  const cloned = clone(['someNestedObj','hello'],obj)
  //Set the new value
  cloned.someNestedObj.hello = 5;

*/
const clone = (arr, state) => {
    let clonedObj = {...state}
    const originalObj = clonedObj;
    arr.forEach(property => {
        if(!(property in clonedObj)){
            throw new Error('State missing property')
        }

        if(isObject(clonedObj[property])){
            clonedObj[property] = {...originalObj[property]};
            clonedObj = clonedObj[property];
        }
    })
    return originalObj;
}

const nestedObj = {
    someProperty:true,
    someNestedObj:{
        someOtherProperty:true
    }
}

const clonedObj = clone(['someProperty'], nestedObj);
console.log(clonedObj === nestedObj) //returns false
console.log(clonedObj.someProperty === nestedObj.someProperty) //returns true
console.log(clonedObj.someNestedObj === nestedObj.someNestedObj) //returns true

console.log()
const clonedObj2 = clone(['someProperty','someNestedObj','someOtherProperty'], nestedObj);
console.log(clonedObj2 === nestedObj) // returns false
console.log(clonedObj2.someNestedObj === nestedObj.someNestedObj) //returns false
//returns true (doesn't attempt to clone because its primitive type)
console.log(clonedObj2.someNestedObj.someOtherProperty === nestedObj.someNestedObj.someOtherProperty) 

0

私はそれが古い質問であることを知っていますが、私がこれをどのように達成したかを共有したかったのです。コンストラクターの状態が次のようであると仮定します

  constructor(props) {
    super(props);

    this.state = {
      loading: false,
      user: {
        email: ""
      },
      organization: {
        name: ""
      }
    };

    this.handleChange = this.handleChange.bind(this);
  }

私のhandleChange機能は次のとおりです:

  handleChange(e) {
    const names = e.target.name.split(".");
    const value = e.target.type === "checkbox" ? e.target.checked : e.target.value;
    this.setState((state) => {
      state[names[0]][names[1]] = value;
      return {[names[0]]: state[names[0]]};
    });
  }

そして、それに応じて入力に名前を付けてください:

<input
   type="text"
   name="user.email"
   onChange={this.handleChange}
   value={this.state.user.firstName}
   placeholder="Email Address"
/>

<input
   type="text"
   name="organization.name"
   onChange={this.handleChange}
   value={this.state.organization.name}
   placeholder="Organization Name"
/>

0

私は削減検索でネストされた更新を行います:

例:

状態のネストされた変数:

state = {
    coords: {
        x: 0,
        y: 0,
        z: 0
    }
}

関数:

handleChange = nestedAttr => event => {
  const { target: { value } } = event;
  const attrs = nestedAttr.split('.');

  let stateVar = this.state[attrs[0]];
  if(attrs.length>1)
    attrs.reduce((a,b,index,arr)=>{
      if(index==arr.length-1)
        a[b] = value;
      else if(a[b]!=null)
        return a[b]
      else
        return a;
    },stateVar);
  else
    stateVar = value;

  this.setState({[attrs[0]]: stateVar})
}

使用する:

<input
value={this.state.coords.x}
onChange={this.handleTextChange('coords.x')}
/>

0

これは私の初期状態です

    const initialStateInput = {
        cabeceraFamilia: {
            familia: '',
            direccion: '',
            telefonos: '',
            email: ''
        },
        motivoConsulta: '',
        fechaHora: '',
        corresponsables: [],
    }

フックまたは状態(クラスコンポーネント)に置き換えることができます。

const [infoAgendamiento, setInfoAgendamiento] = useState(initialStateInput);

handleChangeのメソッド

const actualizarState = e => {
    const nameObjects = e.target.name.split('.');
    const newState = setStateNested(infoAgendamiento, nameObjects, e.target.value);
    setInfoAgendamiento({...newState});
};

ネストされた状態を持つ状態を設定する方法

const setStateNested = (state, nameObjects, value) => {
    let i = 0;
    let operativeState = state;
    if(nameObjects.length > 1){
        for (i = 0; i < nameObjects.length - 1; i++) {
            operativeState = operativeState[nameObjects[i]];
        }
    }
    operativeState[nameObjects[i]] = value;
    return state;
}

最後に、これは私が使用する入力です

<input type="text" className="form-control" name="cabeceraFamilia.direccion" placeholder="Dirección" defaultValue={infoAgendamiento.cabeceraFamilia.direccion} onChange={actualizarState} />

0

プロジェクトでformikを使用している場合、これを簡単に処理できます。これが、formikを使用する最も簡単な方法です。

最初に、formik initivalues属性内または反応で初期値を設定します。状態

ここでは、初期値は反応状態で定義されています

   state = { 
     data: {
        fy: {
            active: "N"
        }
     }
   }

formik initiValues属性内のformikフィールドの上記の初期値を定義します

<Formik
 initialValues={this.state.data}
 onSubmit={(values, actions)=> {...your actions goes here}}
>
{({ isSubmitting }) => (
  <Form>
    <Field type="checkbox" name="fy.active" onChange={(e) => {
      const value = e.target.checked;
      if(value) setFieldValue('fy.active', 'Y')
      else setFieldValue('fy.active', 'N')
    }}/>
  </Form>
)}
</Formik>

formik 関数のstring代わりにに更新された状態をチェックするコンソールを作成して状態を設定するか、reactデバッガーツールを使用してformik状態の値の変更を確認します。booleansetFieldValue


0

このコードを試してください:

this.setState({ someProperty: {flag: false} });

しかし、これによりsomeProperty、上記のコードが実行されるオブジェクトに存在する他のプロパティが削除され、上記のコードが実行された後、flagプロパティのみが残ります
Yashas

0

私は本で以下を見ました:

this.setState(state => state.someProperty.falg = false);

しかし、それが正しいかどうかはわかりません。

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