問題#
非同期の setup () を使用する場合、最初の await ステートメントの前に効果とライフサイクルフックを使用する必要があります。(詳細)
import { ref, watch, onMounted, onUnmounted } from 'vue'
export default defineAsyncComponent({
async setup() {
const counter = ref(0)
watch(counter, () => console.log(counter.value))
// OK!
onMounted(() => console.log('Mounted'))
// the await statement
await someAsyncFunction() // <-----------
// does NOT work!
onUnmounted(() => console.log('Unmounted'))
// still works, but does not auto-dispose
// after the component is destroyed (memory leak!)
watch(counter, () => console.log(counter.value * 2))
}
})
await ステートメントの後、次の関数は制限されます(自動破棄なし):
watch
/watchEffect
computed
effect
次の関数は機能しません:
onMounted
/onUnmounted
/onXXX
provide
/inject
getCurrentInstance
制限#
非同期関数は、複数のコンポーネント間で共有されるグローバル変数を更新する際に問題を引き起こす可能性があります。setup()
が待機されると、複数のコンポーネントの作成がグローバル変数を変更することができ、予測不可能な状態を作り出し、システム内で混乱を引き起こす可能性があります。setup()
が await ステートメントなしで呼び出されると、最初の await の前にタスクが実行され、実行の一貫性に影響を与えます。Vue は非同期部分が外部から呼び出されるタイミングを予測することができず、したがってインスタンスをコンテキストにバインドすることはできません。
currentInstance = instance
await component.setup() // atomic lost
currentInstance = prev
async function setup() {
console.log(1)
await someAsyncFunction()
console.log(2)
}
console.log(3)
setup()
console.log(4)
// 出力:
3
1
4
(awaiting)
2
解決策#
非同期関数を「リアクティブ同期」としてラップする#
From
const data = await fetch('https://api.github.com/').then(r => r.json())
const user = data.user
To
const data = ref(null)
fetch('https://api.github.com/')
.then(r => r.json())
.then(res => data.value = res)
const user = computed(() => data?.user)
インスタンスを明示的にバインドする#
import { effectScope, onMounted } from 'vue'
export default defineAsyncComponent({
async setup() {
// `await`の前にインスタンスを取得して保持する
const instance = getCurrentInstance()
// `await`の前にスコープを作成し、それをインスタンスにバインドする
const scope = effectScope()
const data = await someAsyncFunction() // <-----------
onMounted(
() => {},
instance // <--- インスタンスを渡す
)
scope.run(() => {
/* `computed`、`watch`などを使用する... */
})
// ここではライフサイクルフックは利用できません
}
})
参考文献:
Anthony Fu: https://antfu.me/posts/async-with-composition-api