ファイル読み込みや書き込みなんかの非同期処理をするときにReactだとどこに書いていいかわからないことがあります。
読み込みに関してはcomponentDidMount
などで呼び出せば配置後に1度だけ呼び出すことはできますが、更新処理でちょっと困ったのでメモ。
まずはReactの処理順序について確認。
CC0ライセンスでわかりやすいライフサイクルがあったのでお借りします。
×を付けたのが将来的に廃止になるライフサイクルです。
componentWillReceiveProps
はgetDerivedStateFromProps
で置き換えることが想定されているためこれを使うのもいいと思います(大きな違いとしてマウント時も呼び出されることは注意する)。
shouldComponentUpdate
は更新有無を判定してチューニングする用みたいなので今回の用途ではないように思います。
操作はDOM構築後にしたいのでconstructor
も除外すると以下を使えます。
マウント時
- getDerivedStateFromProps
- render
- componentDidMount
state/props更新時
- getDerivedStateFromProps
- render
- componentDidUpdate
注意点として、render
、componentDidUpdate
でsetState
などので値更新処理を入れてはいけません。無限ループに陥ります。
また、getDerivedStateFromProps
はそもそもsetState
するものではありません。
これを非同期処理に使えればいいんですが、return
で値を変更する仕様上使えそうにありません。
非同期処理はcomponentDidMount
、componentDidUpdate
に入れて、その場では値更新はしないというのが対処療法でしょうか。
ちゃんと対策するには、非同期処理をPromiseでラップして処理後にsetStateするのが良いと思います。
1 2 3 4 5 6 7 8 9 10 11 |
export function filesave(file){ return new Promise((resolve, reject) => { ... resolve(fullname); }); } ------------------------------------------- filesave(this.state.file).then((name)=>{ //setStateを含む処理呼び出し this.props.handleUpdate(name); }); |
こんな感じで対策していると、同名の画像を更新したときに更新前の画像が表示される問題が起きました。
URLが同一だとキャッシュが表示されたりするので、異なるパラメータを付与することでちゃんと更新されます。
1 2 |
setState({url: someurl + ?t=" + new Date().getTime()}); setState({url: someurl + ?t=" + Math.random().toString(36).slice(-8)}); |
大分回り道しましたが、Reactではよほどのことがない限り更新はsetStateだけを使うのが良いように思います。