自定义 React Native Asyncstorage 挂钩导致奇怪的结果?
Custom React Native Asyncstorage hook causes weird results?
我在 React Native 中有一个项目,它利用 React Navigation 和 Asyncstorage 来存储要由子屏幕编辑的数据。由于我们需要在全局范围内监听每个键的更改,因此我制作了以下使用 EventEmitter 的 Asyncstorage 挂钩:
import AsyncStorage from "@react-native-async-storage/async-storage";
import EventEmitter from "eventemitter3";
import { useEffect, useState } from "react";
const eventEmitter = new EventEmitter();
/**
* Acts as a react hook for AsyncStorage
* @param id - ID of the element
* @param defaultValue - Default value of the element
* @returns A react hook of the element
*/
export default function useStorage<Type>(id: string, defaultValue: Type): [Type, (value: Type) => Promise<void>] {
const [version, setVersion] = useState(0);
const [data, setData] = useState(defaultValue);
// Grab Data
const getData = async () => {
const jsonData = await AsyncStorage.getItem(id);
if (jsonData)
setData(JSON.parse(jsonData) as Type);
};
useEffect(() => { getData(); }, [version]);
// Save Data
const saveData = async (value: Type) => {
const jsonData = JSON.stringify(value);
await AsyncStorage.setItem(id, jsonData);
setData(value);
eventEmitter.emit(id);
}
useEffect(() => {
let isMounted = true;
const handleDataChange = () => {
if (isMounted) {
setVersion(v => v + 1);
}
}
const unmount = () => {
isMounted = false;
eventEmitter.removeListener(id, handleDataChange);
}
eventEmitter.addListener(id, handleDataChange);
return unmount;
}, [id]);
return [data, saveData];
}
然而,每当我使用它时,我都会得到非常奇怪的结果,包括...
- 当同一个键同时出现在父屏幕和子屏幕上时,数据无法正确加载
- 数据未正确更新
- 挂钩未正确清理
我错过了什么吗?是什么导致了所有这些问题?有没有更好的实现方式?
注意:我知道存在 React Redux,但我希望尽可能避免使用它。
在单个函数中调用多个 setStates()
可能会导致意外的副作用。通过将代码调整为每个函数仅使用 1 setState()
,可以避免这些问题。
我在 React Native 中有一个项目,它利用 React Navigation 和 Asyncstorage 来存储要由子屏幕编辑的数据。由于我们需要在全局范围内监听每个键的更改,因此我制作了以下使用 EventEmitter 的 Asyncstorage 挂钩:
import AsyncStorage from "@react-native-async-storage/async-storage";
import EventEmitter from "eventemitter3";
import { useEffect, useState } from "react";
const eventEmitter = new EventEmitter();
/**
* Acts as a react hook for AsyncStorage
* @param id - ID of the element
* @param defaultValue - Default value of the element
* @returns A react hook of the element
*/
export default function useStorage<Type>(id: string, defaultValue: Type): [Type, (value: Type) => Promise<void>] {
const [version, setVersion] = useState(0);
const [data, setData] = useState(defaultValue);
// Grab Data
const getData = async () => {
const jsonData = await AsyncStorage.getItem(id);
if (jsonData)
setData(JSON.parse(jsonData) as Type);
};
useEffect(() => { getData(); }, [version]);
// Save Data
const saveData = async (value: Type) => {
const jsonData = JSON.stringify(value);
await AsyncStorage.setItem(id, jsonData);
setData(value);
eventEmitter.emit(id);
}
useEffect(() => {
let isMounted = true;
const handleDataChange = () => {
if (isMounted) {
setVersion(v => v + 1);
}
}
const unmount = () => {
isMounted = false;
eventEmitter.removeListener(id, handleDataChange);
}
eventEmitter.addListener(id, handleDataChange);
return unmount;
}, [id]);
return [data, saveData];
}
然而,每当我使用它时,我都会得到非常奇怪的结果,包括...
- 当同一个键同时出现在父屏幕和子屏幕上时,数据无法正确加载
- 数据未正确更新
- 挂钩未正确清理
我错过了什么吗?是什么导致了所有这些问题?有没有更好的实现方式?
注意:我知道存在 React Redux,但我希望尽可能避免使用它。
在单个函数中调用多个 setStates()
可能会导致意外的副作用。通过将代码调整为每个函数仅使用 1 setState()
,可以避免这些问题。