简体   繁体   English

在 useEffect 钩子中设置状态和 AsyncStorage 会导致无限循环?

[英]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钩子初始化初始datasetData状态:

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.现在,我使用useEffectuseEffect获取数据并将其设置为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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM