[解決済み] Reactは状態の更新の順番を守るのか?
質問
Reactはパフォーマンスの最適化のために、状態の更新を非同期かつ一括で行うことがありますね。そのため
setState
. しかし、あなたはReactを信頼して
と同じ順序で状態を更新します。
setState
が呼び出されます。
に対して
- は、同じコンポーネントですか?
- 異なるコンポーネント?
以下の例でボタンをクリックすることを考えます。
1. という可能性はないのでしょうか? aは偽であり、bは真である のためのものです。
class Container extends React.Component {
constructor(props) {
super(props);
this.state = { a: false, b: false };
}
render() {
return <Button onClick={this.handleClick}/>
}
handleClick = () => {
this.setState({ a: true });
this.setState({ b: true });
}
}
2. という可能性はないのでしょうか? aは偽であり、bは真である のためのものです。
class SuperContainer extends React.Component {
constructor(props) {
super(props);
this.state = { a: false };
}
render() {
return <Container setParentState={this.setState.bind(this)}/>
}
}
class Container extends React.Component {
constructor(props) {
super(props);
this.state = { b: false };
}
render() {
return <Button onClick={this.handleClick}/>
}
handleClick = () => {
this.props.setParentState({ a: true });
this.setState({ b: true });
}
}
これらは私のユースケースを極端に単純化したものであることに留意してください。例えば、例 1 では両方の状態を同時に更新し、例 2 では最初の状態の更新に対するコールバックで 2 番目の状態の更新を行うなど、別の方法も可能だと思います。しかし、これは私の質問ではなく、私はReactがこれらの状態の更新を実行する明確に定義された方法があるかどうかに興味があるだけで、それ以外のことはありません。
ドキュメントに裏打ちされた回答があれば、非常にありがたいです。
解決方法を教えてください。
私はReactで仕事をしています。
TLDR
しかし、ReactがsetStateが呼ばれたのと同じ順序で状態を更新することを信頼できますか?
- 同じコンポーネントですか?
はい。
- 異なるコンポーネント?
はい。
その オーダー の更新は常に尊重されます。中間状態を見るかどうかは、バッチ内部かどうかに依存します。
現在(React 16以前)。 Reactのイベントハンドラ内の更新のみがデフォルトでバッチ処理されます。 . イベントハンドラの外側で強制的にバッチ処理を行うための不安定なAPIがあるので、それが必要な場合は稀に利用することができます。
将来のバージョン(おそらくReact 17以降)では、Reactはデフォルトですべての更新をバッチ処理するので、このことについて考える必要はありません。この点に関する変更は、いつものように Reactブログ とリリースノートに記載しています。
これを理解するためのポイントは
いくら
setState()
の呼び出しは、どれだけ多くのコンポーネントで
Reactのイベントハンドラ内
の場合、イベント終了時に1回だけ再レンダリングが行われます。
. これは大規模なアプリケーションで良好なパフォーマンスを発揮するために重要です。
Child
と
Parent
各呼び出し
setState()
を再描画したくない場合は、クリックイベントを処理する際に
Child
を2回実行します。
どちらの例でも
setState()
の呼び出しは、Reactのイベントハンドラ内で発生します。したがって、それらは常にイベントの終了時に一緒にフラッシュされます(そして、あなたは中間状態を見ることはありません)。
更新は常に
発生順に浅くマージされる
. したがって、最初のアップデートが
{a: 10}
であり、2番目は
{b: 20}
であり、3番目は
{a: 30}
の場合、レンダリング状態は
{a: 30, b: 20}
. 同じ状態キーに対するより新しい更新(たとえば
a
は常に勝ちます。
その
this.state
オブジェクトは、バッチの終了時にUIを再レンダリングする際に更新されます。そのため、以前の状態に基づいて状態を更新する必要がある場合(カウンターのインクリメントなど)には、機能的な
setState(fn)
バージョンから読み込むのではなく、前の状態を得ることができます。
this.state
. この理由が気になる方は、詳しく説明した
このコメントで
.
この例では、次のような理由で中間状態を見ることはできません。 Reactのイベントハンドラ内 バッチ処理が有効な場合(Reactはいつそのイベントを終了するのかを知っているため)。
ただし、React16でもそれ以前のバージョンでも。
Reactのイベントハンドラ以外では、まだデフォルトでバッチ処理は行われていません。
. したがって、あなたの例では、AJAXレスポンスハンドラの代わりに
handleClick
というように、それぞれの
setState()
が発生すると、即座に処理されます。この場合、そう、あなたは
となります。
は中間状態を見ることができます。
promise.then(() => {
// We're not in an event handler, so these are flushed separately.
this.setState({a: true}); // Re-renders with {a: true, b: false }
this.setState({b: true}); // Re-renders with {a: true, b: true }
this.props.setParentState(); // Re-renders the parent
});
という不便さを実感しています。 イベントハンドラ内かどうかで動作が異なること . これは将来のReactバージョンで変更され、デフォルトですべての更新をバッチ処理するようになります(そして、変更を同期的にフラッシュするためのオプトインAPIを提供します)。デフォルトの挙動を切り替えるまでは(潜在的にはReact 17で)。 強制的にバッチ処理を行うために使用できるAPIがあります。 :
promise.then(() => {
// Forces batching
ReactDOM.unstable_batchedUpdates(() => {
this.setState({a: true}); // Doesn't re-render yet
this.setState({b: true}); // Doesn't re-render yet
this.props.setParentState(); // Doesn't re-render yet
});
// When we exit unstable_batchedUpdates, re-renders once
});
内部的にはReactのイベントハンドラはすべて
unstable_batchedUpdates
そのため、デフォルトでバッチ処理されます。更新を
unstable_batchedUpdates
を2回使っても何の効果もありません。更新は、一番外側の
unstable_batchedUpdates
を呼び出します。
このAPIはquot;unstable"で、すでにデフォルトでバッチングが有効になっている場合は削除される予定です。しかし、マイナーバージョンでは削除されないので、Reactのイベントハンドラ以外のケースでバッチ処理を強制する必要がある場合は、React 17まで安全に頼ることができます。
結論から言うと、Reactはデフォルトではイベントハンドラ内でのみバッチ処理を行うため、このトピックは分かりにくいです。これは将来のバージョンで変更され、その時の動作はより分かりやすくなるでしょう。しかし、解決策としては バッチを減らす それは バッチリ をデフォルトで使用します。それが、私たちがやろうとしていることです。
関連
-
[解決済み】gulp anythingを実行するたびに、アサーションエラーが発生します。- タスク関数を指定する必要があります
-
JSクリックイベント - Uncaught TypeError: プロパティ 'onclick' に null を設定できません。
-
[解決済み] JavaScriptで "use strict "は何をするのか、その根拠は?
-
[解決済み] 私のJavaScriptコードは "No 'Access-Control-Allow-Origin' header is present on requested resource "というエラーを受け取りますが、Postmanはそうならないのはなぜですか?
-
[解決済み] なぜ ++[[]][+[] +[+[]] は "10" という文字列を返すのでしょうか?
-
[解決済み] Facebookがブラウザに統合されたDeveloper Toolsを無効にする方法を教えてください。
-
[解決済み] React NativeとReactの違いは何ですか?
-
[解決済み] Reactのstateとpropsの違いとは?
-
[解決済み] Reactでネストした状態のプロパティを更新する方法
-
[解決済み】関数の前のエクスクラメーションマークは何をするのですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
Vueのイベント処理とイベントモディファイアの解説
-
[解決済み] 配列の結合時に未定義のプロパティ 'push' を読み込むことができない
-
[解決済み】Node.js Error: Cannot find module express
-
[解決済み】gulp anythingを実行するたびに、アサーションエラーが発生します。- タスク関数を指定する必要があります
-
[解決済み】ReactJSでエラー発生 Uncaught TypeError: Super expression は null か関数でなければならず、undefined ではありません。
-
[解決済み】「.addEventListener is not a function」なぜこのエラーが発生するのか?
-
nodejs unhandledPromiseRejectionWarning メッセージ
-
JSクリックイベント - Uncaught TypeError: プロパティ 'onclick' に null を設定できません。
-
OSSアップロードエラーを解決する: net::ERR_SSL_PROTOCOL_ERROR
-
[解決済み】react hooksで`setState`コールバックを使用する方法