私はtodoアプリケーションに取り組んでいます。これは、問題のコードを非常に単純化したバージョンです。チェックボックスがあります:
<p><input type="checkbox" name="area" checked={this.state.Pencil} onChange={this.checkPencil}/> Writing Item </p>
チェックボックスを呼び出す関数は次のとおりです。
checkPencil(){
this.setState({
pencil:!this.state.pencil,
});
this.props.updateItem(this.state);
}
updateItemはreduxへのディスパッチにマップされる関数です
function mapDispatchToProps(dispatch){
return bindActionCreators({ updateItem}, dispatch);
}
私の問題は、updateItemアクションを呼び出してconsole.logの状態を呼び出すと、常に1ステップ遅れていることです。チェックボックスがオフでtrueではない場合、updateItem関数に渡されるtrueの状態を取得します。状態を強制的に更新するために別の関数を呼び出す必要がありますか?
SetStateは非同期に発生するため、2番目の関数をsetStateのコールバックとして呼び出す必要があります。何かのようなもの:
this.setState({pencil:!this.state.pencil}, myFunction)
しかし、あなたの場合、その関数をパラメーターで呼び出す必要があるため、もう少し創造的になり、おそらく小道具で関数を呼び出す独自の関数を作成する必要があります:
myFunction = () => {
this.props.updateItem(this.state)
}
それらを一緒に組み合わせれば、うまくいくはずです。
ReactのsetState()
の呼び出しは、さまざまな理由(主にパフォーマンス)のために非同期です。 Reactは、setState()
への複数の呼び出しを単一の状態変更にバッチ処理し、状態の変更ごとに再レンダリングするのではなく、コンポーネントを一度だけ再レンダリングします。
幸いなことに、解決策はかなり単純です-setState
はコールバックパラメーターを受け入れます。
checkPencil(){
this.setState({
pencil:!this.state.pencil,
}, function () {
this.props.updateItem(this.state);
}.bind(this));
}
現在の状態のプロパティを使用して状態を更新する場合、Reactドキュメントでは、オブジェクトの代わりにsetState
の関数呼び出しバージョンを使用することをお勧めします。
setState((state, props) => {...})
の代わりにsetState(object)
です。
理由は、setState
は即時の変更ではなく、状態の変更を要求するためです。 Reactは、パフォーマンス向上のためにこれらのsetState
呼び出しをバッチ処理します。
チェックしている状態プロパティの意味が安定していない可能性があります。これは注意すべき潜在的な落とし穴です。
詳細については、こちらのドキュメントを参照してください: https://facebook.github.io/react/docs/react-component.html#setstate
あなたの質問に答えるために、私はこれをします。
checkPencil(){
this.setState((prevState) => {
return {
pencil: !prevState.pencil
};
}, () => {
this.props.updateItem(this.state)
});
}
非同期が発生するためです。そのため、その時点ではまだ更新されていない可能性があります。
React v.16ドキュメントによると、オブジェクトではなく関数を受け入れるsetState()
の2番目の形式を使用する必要があります。
状態の更新が非同期になる場合がある
Reactは、パフォーマンスのために複数のsetState()呼び出しを単一の更新にバッチ処理する場合があります。
This.propsとthis.stateは非同期に更新される可能性があるため、次の状態の計算にそれらの値に依存しないでください。
たとえば、次のコードはカウンターの更新に失敗する場合があります。
// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});
これを修正するには、オブジェクトではなく関数を受け入れるsetState()の2番目の形式を使用します。その関数は、前の状態を最初の引数として受け取り、更新が適用されたときの小道具を2番目の引数として受け取ります。
// Correct
this.setState((prevState, props) => ({
counter: prevState.counter + props.increment
}));
最初に値を設定します。作業を進めた後。
this.setState({inputvalue: e.target.value}, function () {
this._handleSubmit();
});
_handleSubmit() {
console.log(this.state.inputvalue);
//Do your action
}
ベンは当面の問題を解決する方法について素晴らしい答えを持っていますが、状態の重複を避けることもお勧めします
状態がreduxの場合、チェックボックスは、独自のコンポーネントとグローバルストアの両方でチェック状態を追跡するのではなく、小道具またはストアから独自の状態を読み取る必要があります
このようなことをしてください:
<p>
<input
type="checkbox"
name="area" checked={this.props.isChecked}
onChange={this.props.onChange}
/>
Writing Item
</p>
一般的なルールは、複数の場所で必要な状態が見つかった場合、それを共通の親(常にリデュースではない)に引き上げて、単一の真実のソースのみを保持することです。
これを試して
this.setState({inputvalue: e.target.value}, function () {
console.log(this.state.inputvalue);
this.showInputError(inputs[0].name);
});
フォームを使用する場合の検証用のshowInputError関数
RossipediaとBen Hareの両方の提案を使用して、次のことを行いました。
checkPencil(){
this.setState({
pencil:!this.state.pencil,
}, this.updatingItem);
}
updatingItem(){
this.props.updateItem(this.state)
}