react-native - React-Native - useEffect 导致无限循环
问题描述
我试图在我的组件中显示一些动态内容,但不知何故 useEffect 会导致无限循环。
可能是什么问题?
useEffect(() => {
retrieveLocalData('following').then((contacts) => {
setLocalData(JSON.parse(contacts));
});
}, [getLocalData]);
async function retrieveLocalData(key) {
try {
return await AsyncStorage.getItem(key);
} catch (error) {
console.log(error);
}
}
console.log('test'); // infinite
解决方案
更新的答案
无限循环是useEffect
钩子更新触发钩子首先运行的相同值的结果。
下面是一个简单的例子来说明这个问题:
const [value, setValue] = useState({ foo: 'bar' });
useEffect(() => {
Promise.resolve('{"foo":"bar"}').then((result) => {
const newValue = JSON.parse(result);
// `newValue` is a new object, even if its content is identical to `value`.
setValue(newValue);
});
}, [value]);
在这个例子中,当value
设置时,它会导致useEffect
钩子执行,它会异步更新value
一个新对象,这将导致useEffect
钩子再次执行,依此类推。即使对象的内容相同,JSON.parse
调用也会创建一个具有新引用的新对象。
您可以通过在更新状态之前对两个对象进行深度相等检查来防止无限循环。使用类似Lodash 的isEqual
函数可以让这变得非常简单。
useEffect(() => {
Promise.resolve('{"foo":"bar"}').then((result) => {
setValue((prev) => {
const newValue = JSON.parse(result);
// Do a deep comparison and only update state with new object if content is different.
return isEqual(prev, newValue) ? prev : newValue;
});
});
}, [value]);
在这个例子中,只有当对象的内容不同时,对的引用value
才会改变。
但是,这只能说明问题所在。我不确定您的问题的正确解决方案是什么,因为不清楚为什么组件只需要在状态更改时将数据从本地存储加载到状态中,但状态仅在从本地存储加载时才会更新。这里似乎存在“先有鸡还是先有蛋”的问题。感觉应该有其他东西应该触发将数据从本地存储加载到状态,而不是刚刚从本地存储加载到状态的数据。
上一个答案
这里可能的罪魁祸首是钩子getLocalData
的依赖列表。useEffect
如果这不是一个稳定的引用(即每次渲染时引用发生变化),那么它将导致useEffect
钩子执行,然后触发状态更新,这将触发渲染,这将导致useEffect
再次执行,从而启动整个事情重新来过。
在示例代码中,不清楚getLocalData
来自哪里。无论它来自哪里,您都可以考虑用useCallback
钩子包装它以创建稳定的引用。如果这只是一个错字并且是retrieveLocalData
,那么这绝对是问题所在。因为retrieveLocalData
在组件的渲染函数内部声明,所以它会在每次渲染时创建一个新的函数实例(带有新的引用)。
我只是将它移到useEffect
钩子内并消除依赖关系。
useEffect(() => {
AsyncStorage.getItem('following')
.then((contacts) => {
setLocalData(JSON.parse(contacts));
})
.catch((error) => {
console.log(error);
});
}, []);
推荐阅读
- blazor - 悬停并更改图像
- r - 查找自上次面板数据更改以来的累积值变化和时间
- php - Gdex woocommerce 安装问题?
- android - 在 Android 10 中擦除数据后保留文件
- html - 这里的“&&”运算符背后的逻辑是什么?
- react-native - 每分钟左右发送一次位置数据,有什么解决方案吗?
- amazon-web-services - 使用现有 EC2 实例和 AWS-CDK 创建网络负载均衡器 (NLB)
- javascript - POST 请求循环访问 8 个不同的 url
- laravel - 通过 nginx 限制 laravel 路由
- php - curl 中的 API 密钥