Reactjs – Setting state along with AsyncStorage in useEffect hook causes infinite loop

asyncstoragereact-hooksreact-nativereactjs

I'm new to hooks and recently started using hooks in my React Native projects.

I'm building a simple todo app using the AsyncStorage. First I initialize initial data and setData state using useState hook:

const [data, setData] = useState([]);

There are two textInput and submit button that I use to save data to AsyncStorage. Here is the saveData function:

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. 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 i.e. each time I save data in AsyncStorage. But this is causing infinite loop as setData causes useEffect to run infinitely.

If I remove data from the [] it doesn't loop but my data in render is one step behind. 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.

Best Answer

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.

The solution here is to not use useEffect and instead setData whenever you are setting value in AsyncStorage

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();
};
Related Topic