在 useEffect 挂钩中将状态与 AsyncStorage 一起设置会导致无限循环?
Setting state along with AsyncStorage in useEffect hook causes infinite loop?
我是 hooks
的新手,最近开始在我的 React Native 项目中使用钩子。
我正在使用 AsyncStorage
构建一个简单的待办事项应用程序。首先,我使用 useState
hook:
初始化初始 data
和 setData
状态
const [data, setData] = useState([]);
我使用两个 textInput
和提交按钮将数据保存到 AsyncStorage。这是 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();
};
现在,我正在使用 useEffect
从 AsyncStorage 获取数据并将其设置为 data
状态。我正在使用数据在屏幕上呈现文本。
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);
}
};
我在 useEffect 中使用 [data]
因为我想在每次数据更改时重新渲染我的组件,即每次我将数据保存在 AsyncStorage 中。但这会导致无限循环,因为 setData
导致 useEffect 无限地 运行。
如果我从 []
中删除 data
它不会循环,但我在渲染中的数据落后了一步。因此,每当我保存数据时,它不会显示当前数据,而是显示前一个数据。
任何关于我在这里做错了什么的解释以及我该如何解决这个问题?
谢谢。
正如您已经提到的,无限循环是由于您将 data
作为依赖项传递给 useEffect
并且还在 useEffect 中调用的函数中设置。
这里的解决方案是在 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();
};
只需添加一个条件标志,retrieve
来包装异步存储,retrieveData()
,调用。
同样在 "saving data" 的上下文中,我可能只是将异步存储逻辑与状态逻辑分开。当前 saveData
被状态和异步存储逻辑污染。
类似于:
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()
}
那么效果的目标就是运行 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]);
我是 hooks
的新手,最近开始在我的 React Native 项目中使用钩子。
我正在使用 AsyncStorage
构建一个简单的待办事项应用程序。首先,我使用 useState
hook:
data
和 setData
状态
const [data, setData] = useState([]);
我使用两个 textInput
和提交按钮将数据保存到 AsyncStorage。这是 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();
};
现在,我正在使用 useEffect
从 AsyncStorage 获取数据并将其设置为 data
状态。我正在使用数据在屏幕上呈现文本。
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);
}
};
我在 useEffect 中使用 [data]
因为我想在每次数据更改时重新渲染我的组件,即每次我将数据保存在 AsyncStorage 中。但这会导致无限循环,因为 setData
导致 useEffect 无限地 运行。
如果我从 []
中删除 data
它不会循环,但我在渲染中的数据落后了一步。因此,每当我保存数据时,它不会显示当前数据,而是显示前一个数据。
任何关于我在这里做错了什么的解释以及我该如何解决这个问题?
谢谢。
正如您已经提到的,无限循环是由于您将 data
作为依赖项传递给 useEffect
并且还在 useEffect 中调用的函数中设置。
这里的解决方案是在 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();
};
只需添加一个条件标志,retrieve
来包装异步存储,retrieveData()
,调用。
同样在 "saving data" 的上下文中,我可能只是将异步存储逻辑与状态逻辑分开。当前 saveData
被状态和异步存储逻辑污染。
类似于:
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()
}
那么效果的目标就是运行 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]);