[英]Setting state along with AsyncStorage in useEffect hook causes infinite loop?
I'm new to hooks
and recently started using hooks in my React Native projects.我是hooks
新手,最近开始在我的 React Native 项目中使用钩子。
I'm building a simple todo app using the AsyncStorage
.我正在使用AsyncStorage
构建一个简单的待办事项应用程序。 First I initialize initial data
and setData
state using useState
hook:首先,我使用useState
钩子初始化初始data
和setData
状态:
const [data, setData] = useState([]);
There are two textInput
and submit button that I use to save data to AsyncStorage.我使用两个textInput
和 submit 按钮将数据保存到 AsyncStorage。 Here is the saveData
function:这是saveData
函数:
const saveData = async () => {
const arrData = [{ name: 'vikrant', phone: 123456 }]; // [{ name, phone}] from the textInput
const storedData = await AsyncStorage.getItem('user');
const storedDataParsed = JSON.parse(storedData);
let newData = [];
if (storedData === null) {
// save
await AsyncStorage.setItem('user', JSON.stringify(arrData));
} else {
newData = [...storedDataParsed, user];
await AsyncStorage.setItem('user', JSON.stringify(newData));
}
setName('');
setPhone('');
Keyboard.dismiss();
};
Now, I'm using useEffect
to get data from the AsyncStorage and setting it to the data
state.现在,我使用useEffect
从useEffect
获取数据并将其设置为data
状态。 I'm using data to render the text in the screen.我正在使用数据在屏幕中呈现文本。
useEffect(() => {
retrieveData();
}, [data]);
const retrieveData = async () => {
try {
const valueString = await AsyncStorage.getItem('user');
const value = JSON.parse(valueString);
setData(value);
} catch (error) {
console.log(error);
}
};
I'm using [data]
in useEffect since I want to re-render my component each time data changes ie each time I save data in AsyncStorage.我在 useEffect 中使用[data]
,因为我想在每次数据更改时重新渲染我的组件,即每次我在 AsyncStorage 中保存数据时。 But this is causing infinite loop as setData
causes useEffect to run infinitely.但这会导致无限循环,因为setData
导致 useEffect 无限运行。
If I remove data
from the []
it doesn't loop but my data in render is one step behind.如果我从[]
删除data
,它不会循环,但渲染中的数据落后一步。 So whenever I save data it doesn't show the current data but the previous one.因此,每当我保存数据时,它都不会显示当前数据,而是显示前一个数据。
Any explanation of what I am doing wrong here and how can i fix this?对我在这里做错了什么的任何解释以及我该如何解决这个问题?
Thanks.谢谢。
As already mentioned by you, the infinite loop is due to thefact that you pass data
as a dependency to useEffect
and also set in inside the function called in useEffect.正如您已经提到的,无限循环是由于您将data
作为依赖项传递给useEffect
并在 useEffect 中调用的函数内部进行设置。
The solution here is to not use useEffect and instead setData whenever you are setting value in AsyncStorage这里的解决方案是在 AsyncStorage 中设置值时不使用 useEffect 而是使用 setData
const saveData = async () => {
const arrData = [{ name: 'vikrant', phone: 123456 }]; // [{ name, phone}] from the textInput
const storedData = await AsyncStorage.getItem('user');
const storedDataParsed = JSON.parse(storedData);
let newData = [];
if (storedData === null) {
// save
await AsyncStorage.setItem('user', JSON.stringify(arrData));
} else {
newData = [...storedDataParsed, user];
await AsyncStorage.setItem('user', JSON.stringify(newData));
}
setName('');
setPhone('');
setData(newData);
Keyboard.dismiss();
};
Just add a conditional flag, retrieve
to wrap async storage, retrieveData()
, calls.只需添加一个条件标志, retrieve
包装异步存储, retrieveData()
,调用。
Also in the context of "saving data" I would probably just separate async storage-ish logic with state logic.同样在“保存数据”的上下文中,我可能只是将异步存储逻辑与状态逻辑分开。 Current saveData
is polluted with both state and async storage logic.当前的saveData
受到状态和异步存储逻辑的污染。
Something like:就像是:
const [retrieve, setRetrieve] = useState(false);
// Pure AsyncStorage context
const saveData = async () => {
...
if (storedData === null) {
await AsyncStorage.setItem('user', JSON.stringify(arrData));
} else {
newData = [...storedDataParsed, user];
await AsyncStorage.setItem('user', JSON.stringify(newData));
}
// XXX: Removed state logic, call it somewhere else.
};
const someHandler = async () => {
await saveData();
setRetrieve(true); // to signal effect to call retrieveData()
}
Then the goal of the effect is just to run retrieveData()
once saving is done.然后效果的目标就是在保存完成后运行retrieveData()
。
const [data, setData] = useState([]);
useEffect(() => {
const retrieveData = async () => {
try {
const valueString = await AsyncStorage.getItem('user');
const value = JSON.parse(valueString);
// Other set states
setData(value);
} catch (error) {
console.log(error);
}
};
// Retrieve if has new data
if (retrieve)
retrieveData();
setRetrieve(false);
}
}, [retrieve]);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.