Reading Asyncstorage generates an infinite loop

Asked

Viewed 83 times

0

I have a problem with my applications. I use a lot of useState(), but I have been observing that this is generating endless loops in my application. Follow an example:

if(show){
   AsyncStorage.getItem('PEDIDO').then(value => {
      console.warn(value)
   });
}

This code is in a functional component, where it performs the function of a modal. For example, the user clicks on a button and this component enters the screen, the property show represents when the component is on the screen. The result is an infinite loop showing the parameter value, if I use the following code:

if(show){
   AsyncStorage.getItem('PEDIDO').then(value => {
      setPedido(JSON.parse(value));
   });
}

How can I solve this infinite loop problem?

  • This access needs to be in a useEffect(), if it stays in the body of the function (component), it will perform on each render (and will cause a new render because of the setPedido)

  • The use of useEffect was a very good solution, thank you very much!!

3 answers

0

Hello, all right?

A suggestion is, by the excerpt of the code I can not identify for sure what is causing the "error", I recommend that you remove the . then and place an async and await in the Asyncstorage call

Would look this way:

  const nomeDoMetodo = async () => {
    if(show){
          let pedido = await AsyncStorage.getItem('PEDIDO');
          setPedido(JSON.parse(pedido));
    }
}
  • This method continues to generate the loop... but thank you for responding!

0

You should not be accessing Asyncstorage all the time.

const [fetchStorage, setFetchStorage] = useState(true);

if(show){
   if (fetchStorage) {
       AsyncStorage.getItem('PEDIDO').then(value => {
          setPedido(JSON.parse(value));
       }); 
       setFetchStorage(false)
   }
   //restante do código referente ao modal
}

This way, you will only access the Storage once, searching for the item and saving in the state.

I hope it helps!

0


Your access to AsyncStorage is in an infinite loop because you are performing this access in the body of its functional component, that is, with each rendering you are getting the data from the AsyncStorage, updating the state and performing a new access (loop).

I performed an example below the call of an asynchronous function (with setTimeOut) being executed in the body of the function if show === true:

function Componente() {
  const [date, setDate] = React.useState('');
  const [show, setShow] = React.useState(false);
  
  React.useEffect(() => {
    setShow(true);
  }, []);

  function getDateAsync() {
    setTimeout(function() {
      console.log('Leitura assíncrona realizada');
      const now = (new Date()).toString();
      setDate(now);
    }, 1000);
  }

  if (show) {
    getDateAsync();
  }

  console.log("[RENDER] show:", show);
  return date ? <p>Data obtida: {date}</p> : <p>Carregando...</p>;
}

ReactDOM.render( <Componente /> , document.querySelector("#app"));
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>

<div id="app"></div>

To solve this, the ideal solution is to make use of Hook useEffect:

What the useEffect does? Using this Hook, you tell React that the component needs to do something only after rendering.

Then we’ll make a useEffect which will be called whenever changing the state of show, but we want to execute the getDateAsync() only if show for true, then we create a condition too:

function Componente() {
  const [date, setDate] = React.useState('');
  const [show, setShow] = React.useState(false);
  
  React.useEffect(() => {
    setShow(true);
  }, []);

  React.useEffect(() => {
    // Criando uma função desta maneira, você pode inclusive fazer uso de
    // async/await para obter o resultado do AsyncStorage.
    function getDateAsync() {
      setTimeout(function() {
        console.log('Leitura assíncrona realizada');
        const now = (new Date()).toString();
        setDate(now);
      }, 1000);
    }

    if (show) {
      getDateAsync();
    }
  }, [show]);

  console.log("[RENDER] show:", show);
  return date ? <p>Data obtida: {date}</p> : <p>Carregando...</p>;
}

ReactDOM.render( <Componente /> , document.querySelector("#app"));
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>

<div id="app"></div>

Note that there have been almost no code changes, but in this way we make good use of Hooks and the code performs the behavior expected by the user.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.