ReactJSプロジェクトでは、abelでawaitを使用しています。 React setStateの便利な使い方を発見しました。次のコードを検討してください。
handleChange = (e) => {
this.setState({[e.target.name]: e.target.value})
console.log('synchronous code')
}
changeAndValidate = async (e) => {
await this.handleChange(e)
console.log('asynchronous validation code')
}
componentDidUpdate() {
console.log('updated component')
}
私の意図は、コンポーネントの更新後に非同期検証コードを実行することでした。そしてそれは動作します!結果のコンソールログは次を示します:
synchronous code
updated component
asynchronous validation code
検証コードは、handleChangeが状態を更新し、新しい状態がレンダリングされた後にのみ実行されます。
通常、状態が更新された後にコードを実行するには、this.setStateの後にコールバックを使用する必要があります。つまり、handleChangeの後に何かを実行する場合は、コールバックパラメーターを指定してからsetStateに渡す必要があります。可愛くない。しかし、コード例では、状態が更新された後にhandleChangeが完了したことを何らかの方法で待機しています...しかし、待機はプロミスでのみ機能し、続行する前にプロミスが解決するのを待つと思いました。 handleChangeには約束も解決もありません...何を待つべきかをどのように知るのですか?
これは、setStateが非同期に実行され、awaitが完了したことを何らかの形で認識していることを意味するようです。 setStateが内部でpromiseを使用している可能性がありますか?
バージョン:
反応:「^ 15.4.2」
babel-core: "^ 6.26.0"
babel-preset-env: "^ 1.6.0"、
babel-preset-react: "^ 6.24.1"、
babel-preset-stage-0: "^ 6.24.1"
babel-plugin-system-import-transformer: "^ 3.1.0"、
babel-plugin-transform-decorators-legacy: "^ 1.3.4"、
babel-plugin-transform-runtime: "^ 6.23.0"
this.handleChange、awaitの右側で、次を実行します。
2.1。 setStateはアップデーターを実行しますが、setStateはすぐに更新することを保証しないため、更新が後で発生するようにスケジュールする可能性があります(即時であるか後の時点であるかは関係ありません、重要なのはスケジュールされていることだけです)
2.2。 console.log( 'synchronous code')実行...
2.3。 this.handleChangeその後、リターンを終了ndefined(明示的に指定されていない限り、関数はundefinedを返すため、undefinedを返します)
await次にこれを取りますndefinedそして、それは約束ではないので、それを解決された約束に変換しますPromise.resolve(undefined)を使用して、それ-舞台裏で非同期の。thenメソッドに渡されるため、すぐには利用できません:
「Promiseに渡されたコールバックは、JavaScriptイベントループの現在の実行が完了する前に呼び出されることはありません。」
3.1。これは、-ndefinedがevent queue、の後ろに配置されることを意味します(つまり、イベントでsetStateアップデータの背後にあることを意味します)キュー…)
イベントループ最後に到達し、setStateアップデートを取得します。
イベントループ到達してピックアップ未定義、これは未定義に評価されます(必要であればこれを保存できます) 、したがって、=は解決された結果を保存するためにawaitの前に一般的に使用されます)
5.1。 Promise.resolve()が終了しました。つまり、awaitはもはや有効ではないため、残りの関数は再開できます。
私はまだこれをテストしていませんが、ここで私が起こっていると思うことは次のとおりです。
undefined
によって返されるawait
は、setState
コールバックの後にキューに入れられます。 await
は(Promise.resolve
の下で)regenerator-runtime
を実行しており、イベントループの次のアイテムに制御を渡します。
したがって、setState
コールバックがawait
より先にキューに入れられることは偶然です。
これをテストするには、setState
の周りにsetTimeout(f => f、0)を配置します。
babel
のregenerator-runtime
は、基本的にPromise.resolve
を使用して制御を生成するループです。 _ asyncToGenerator の内部を見ることができ、Promise.resolve
があります。
rv
またはawaitの戻り値は次のように定義されます。
rv
Returns the fulfilled value of the promise, or the value itself if it's not a Promise.
したがって、handleChangeは非同期値でもプロミス値でもないため、単純に自然な値を返します(この場合、戻り値はないので、undefined
)。したがって、「handleChangeが完了したことを知らせる」ための非同期イベントループトリガーはありません。単に指定した順序で実行されるだけです。
setState()
は常にコンポーネントをすぐに更新するわけではありません doc
しかし、ここではそうかもしれません。
コールバックをpromiseに置き換えたい場合は、自分で実装できます。
setStateAsync(state) {
return new Promise((resolve) => {
this.setState(state, resolve)
});
}
handleChange = (e) => {
return this.setStateAsync({[e.target.name]: e.target.value})
}
参照: https://medium.com/front-end-hacking/async-await-with-react-lifecycle-methods-802e7760d802