Reactjs 在useEffect钩子中设置状态和异步存储会导致无限循环吗?

Reactjs 在useEffect钩子中设置状态和异步存储会导致无限循环吗?,reactjs,react-native,react-hooks,asyncstorage,Reactjs,React Native,React Hooks,Asyncstorage,我不熟悉挂钩,最近开始在我的React原生项目中使用挂钩 我正在使用AsyncStorage构建一个简单的todo应用程序。首先,我使用useStatehook初始化初始data和setData状态: const [data, setData] = useState([]); 我使用两个textInput和submit按钮将数据保存到异步存储。以下是saveData功能: const saveData = async () => { const arrData = [{ name:

我不熟悉挂钩,最近开始在我的React原生项目中使用挂钩

我正在使用
AsyncStorage
构建一个简单的todo应用程序。首先,我使用
useState
hook初始化初始
data
setData
状态:

const [data, setData] = useState([]);
我使用两个
textInput
和submit按钮将数据保存到异步存储。以下是
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();
};
现在,我使用
useffect
从异步存储中获取数据,并将其设置为
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);
  }
};
我正在使用useffect中的
[data]
,因为每次数据更改时,即每次将数据保存在异步存储中时,我都要重新呈现组件。但这会导致无限循环,因为
setData
会导致useffect无限运行

如果我从
[]
中删除
数据
,它不会循环,但渲染中的数据落后一步。因此,每当我保存数据时,它不会显示当前数据,而是显示上一个数据

我在这里做错了什么,有什么解释吗?我怎样才能解决这个问题


谢谢。

正如您已经提到的,无限循环是由于您将
数据
作为对
useffect
的依赖项传递,并且在useffect中调用的函数中进行设置

这里的解决方案是不使用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()
,调用

同样在“保存数据”的上下文中,我可能只是将异步存储逻辑与状态逻辑分开。当前的
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]);

好吧,那么就不需要使用效果了?让我试着用你的方式做。让我试试这个。谢谢。循环问题已修复,但保存时数据未呈现。@vikrantnegi007已更新。我已经检查过,
data
不需要处于
useffect
依赖关系中。这个效果的目标只是从异步存储中检索,或者不从异步存储中检索。我删除了数据,但问题仍然存在。不确定原因。@vikrantnegi007指调用
saveData()后如何设置标志。