2017-03-17 8 views
1

正しく動作しないコードがいくつかあります。キーと値を親コンポーネントのsetState()に送信するonChangeハンドラがあります。ループオーバー状態でオブジェクトが存在するかどうかをチェック

_onAttributeChange(key, value) { 
    const changes = this.state.changes; 
    const pushObj = {key: key, value: value}; 
    console.log(pushObj); 
    if (changes.length === 0) { 
     this.setState({changes: changes.concat([pushObj])}); 
    } else { 
     changes.forEach(change => { 
      if (change.key === key) { 
       console.log('Update'); 
      } else { 
       console.log('No update'); 
       this.setState({changes: changes.concat([pushObj])}); 
      } 
     }); 
    } 
} 

あなたは、私が{key: 1, value: 'Some Value'}のようになります。キー値のパラメータに基づいてオブジェクトを作成しています。このコードから見ることができます。目標は、配列の長さが0の場合は配列に連結することです。その部分は正常に動作します。 forEachは私が問題を抱えている場所です。私の目標は、ステート配列をループし、入ってくるchange.keyが配列内のキーと一致するかどうかをチェックし、そうでなければ、更新を実行するかどうかを確認します。そうでなければ、 。

だから、2つの質問:まず

  • 、最初の変更が入ってくると、ループが正常に動作し、ちょうど同じ鍵(すなわち、1)と連続する各変化に対してUpdateをログコンソールます。別の変更が入ると、最初は正しく動作して配列に連結しますが、2のキーで連続して変更すると、Updateのコンソールログとelse節が起動します。

  • 第2に、状態を直接変更することなく配列をループしながら変更をどのように更新できますか?

+0

私の回答はまったく役に立ちましたか?もしそうなら、それを「受け入れ」とマークすることを検討してください。そうでない場合、私がどのように助けることができるか教えてください。 – Chris

+0

@Chris Chrisについては申し訳ありません。私は実際にこれを尋ねる前に胃インフルエンザに襲われたので、先日までそれを確認することさえなかった。私はそれが間違いなく解決策であるとしてあなたの答えを受け入れました! – Jake

+0

問題ありません。うれしいことです:) – Chris

答えて

2

答えは非常に単純です。一時的な状態のコピーを作成してから、実際の状態をコピーで置き換えてください。

_onAttributeChange(key, value) { 
    let changes = this.state.changes.slice(); 
    const pushObj = {key: key, value: value}; 
    console.log(pushObj); 
    if (changes.length === 0) { 
    changes = changes.concat([pushObj]); 
    } else { 
    changes.forEach(change => { 
     if (change.key === key) { 
     console.log('Update'); 
     } else { 
     console.log('No update'); 
     changes = changes.concat([pushObj]); 
     } 
    }); 
    } 
    this.setState({changes: changes}); 
} 

あなたは連続した変化であるし、問題は最も可能性の高いsetState()の非同期性に関連しています。このような呼び出しの結果、不要な再レンダリングが発生するだけでなく、ほとんどの場合、望ましくない方法で状態が更新されます。

setState()

はすぐ this.stateを変異させたが 保留の状態遷移を作成しません:

setState()言う公式ドキュメントを反応させるのを見てください。この メソッドを呼び出した後に this.stateにアクセスすると、既存の値が返される可能性があります。 setStateへの呼び出しの同期操作を保証する はなく、パフォーマンス向上のために を呼び出してもよいでしょう。

したがって、実際にループ内の前の繰り返しから更新された状態値を実際に必要とするときは、「古い」状態値を返す可能性があります。


ここで注意すべきもう一つの非常に重要なことは、あなたが取り組んでいる国有財産のコピーを作成する必要があるということです。それ以外の場合は、状態を直接変更することになりますが、これはうまくいく可能性がありますが、お勧めしません。

だから基本的に常に実行します。slice()Object.assign()ためのMDNに

//To copy an array 
let arr = this.state.myArray; //wrong. arr still references myArray 
let arr = this.state.myArray.slice(); //correct 

//To copy an object 
let obj = this.state.myObject; //wrong. obj still references myObject 
let obj = Object.assign({}, this.state.myObject); //correct 

詳細情報を。

また、constは控えめに使用してください。変数でなければならない場合にのみ使用してください。


TL; DRは - 常に最初のすべてのロジックを行い、その後、はあなたの状態の変更をコミットします。

+0

"更新なし"の行の ':'ではなく '='でなければなりません。 – squgeim

+0

@ squiIm良い目です。ありがとう。 – Chris

関連する問題