あるとき重めの処理の中に async 関数が入り await が必要になりました
レンダリング処理の途中に await は書けないです
await しないと useMemo の結果は Promise です
const promise = useMemo(() => {
return fn(foo, bar)
}, [fn, foo, bar])
こんなことを考えてみましたが React ではプロパティが途中で変わっても再レンダリングされなければ画面に影響しません
const value = useMemo(() => {
const result = {
value: null,
}
fn(foo, bar).then(result_value => {
result.value = result_value
})
return result
}, [fn, foo, bar])
resolve されたタイミングで再レンダリングさせるには state を更新するしかないです
setState するなら useEffect の中なのでこんな感じになります
useEffect(() => {
const promise = fn(foo, bar)
setState(null)
promise.then(result => {
setState(result)
})
}, [fn, foo, bar])
できれば避けたいやつです
毎回そういう事するのは避けたいのでフック化してこういう感じです
const usePromise = (promise) => {
const [value, setValue] = useState(null)
promise.then(result => setValue(result))
return value
}
const value = usePromise(promise)
ただこれだけだと promise が変わったときにリセットできないのでやはり useEffect は必要です
また何度も then で関数を設定することになるので 1 回だけで済むように useEffect の中で行うようにします
const usePromise = (promise) => {
const [value, setValue] = useState(null)
useEffect(() => {
setValue(null)
let alive = true
promise.then(result => {
alive && setValue(result)
})
return () => {
alive = false
}
}, [promise])
return value
}
const value = usePromise(promise)
引数の Promise は state に入れたり useMemo を使って同じ Promise を渡すようにしないと無限ループになります
const value = usePromise(Promise.resolve(1))
だと then の中で setValue(1) が実行されて再レンダリングされるたびに Promise が新しくなり また useEffect 内で then がセットされてのループです
ちょっとした使い方のミスで無限ループするのは扱いづらいのかもしれないです