反応ネイティブアプリケーションで、多くのFirestoreスナップショットを使用しています。 Reactフックも使用しています。コードは次のようになります。
_useEffect(() => {
someFirestoreAPICall().onSnapshot(snapshot => {
// When the component initially loads, add all the loaded data to state.
// When data changes on firestore, we receive that update here in this
// callback and then update the UI based on current state
});;
}, []);
_
最初は、useState
がUIの保存と更新に最適なフックであると最初に思いました。しかし、私のuseEffect
フックが空の依存関係配列で設定されている方法に基づいて、スナップショットコールバックが更新されたデータで起動され、現在の状態を新しい変更で変更しようとすると、現在の状態は未定義です。これは閉鎖のためだと思います。私はuseRef
をforceUpdate()
と一緒に使用してそれを回避することができます:
_const dataRef = useRef(initialData);
const [, updateState] = React.useState();
const forceUpdate = useCallback(() => updateState({}), []);
useEffect(() => {
someFirestoreAPICall().onSnapshot(snapshot => {
// if snapshot data is added
dataRef.current.Push(newData)
forceUpdate()
// if snapshot data is updated
dataRef.current.find(e => some condition) = updatedData
forceUpdate()
});;
}, []);
return(
// JSX that uses dataRef.current directly
)
_
私の質問は、useRef
の代わりにforceUpdate
とともにuseState
を使用して別の方法でこれを正しく行うことですか?アプリ全体でuseRef
フックを更新してforceUpdate()
を呼び出す必要があるのは正しくないようです。 useState
を試してみると、依存変数の配列に状態変数を追加しようとしましたが、無限ループになってしまいました。スナップショット関数を1回だけ初期化し、コンポーネントのステートフルデータをバックエンド(onSnapshotコールバックで発生する)での変更に応じて時間の経過とともに更新したいだけです。
UseEffectとuseStateを組み合わせたほうがよいでしょう。 UseEffectはリスナーをセットアップおよびデタッチします。useStateは必要なデータを処理するだけです。
const [data, setData] = useState([]);
useEffect(() => {
const unsubscribe = someFirestoreAPICall().onSnapshot(snap => {
const data = snap.docs.map(doc => doc.data())
this.setData(data)
});
//remember to unsubscribe from your realtime listener on umount or you will create a memory leak
retun () => unsubscribe()
}, []);
次に、アプリのuseStateフックからdata
を参照するだけです。
OnSnapshot()メソッドの内部で状態にアクセスできないことがわかりました(たとえば、console.log(state)の場合、空の値が返されます。
ヘルパー関数を作成することはうまくいきましたが、これがhack-yソリューションであるかどうかはわかりませんが、次のようなものです:
[state, setState] = useState([])
stateHelperFunction = () => {
//update state here
setState()
}
firestoreAPICall.onSnapshot(snapshot => {
stateHelperFunction(doc.data())
})