0

i want to pass the string from asyncstorage to a state variable using hooks, but it doesn't work, trying for hours but still doesn't work. here is the code:

const [cartitems, cartitemsfunc] = useState('');

const d = async () => {
let items = await AsyncStorage.getItem('items');
console.log('items from cart:' + items);
cartitemsfunc(items);
console.log('items from cart2:' + cartitems);
 };

d();

when i try console logging cartitems it logs an empty string in the console,but items logs out the string

can someone please tell me where i went wrong

thanks in advance!!!

skyboyer
  • 22,209
  • 7
  • 57
  • 64
lcl code base
  • 101
  • 2
  • 9
  • add ```await``` in front of ```cartitemsfunc(items);```, if you want the expeted ```console.log```, as cartitemsfunc is ```async``` aswell. – CevaComic Jun 18 '20 at 21:35
  • `useState` is not synchronous. `cartitemsfunc(items)` is run async so the value may not be updated before you run `console.log` on the next line – Samuel Goldenbaum Jun 18 '20 at 21:37
  • @CevaComic i tried that i didn't work – lcl code base Jun 18 '20 at 21:39
  • @SamuelG so how do u suggest i go about it because i can't use items outside the function and i can't also use the state outside the function too – lcl code base Jun 18 '20 at 21:44
  • Basically your state changes, you just get the wrong console.log because is not yet updated during the execution of ```d()```. as @ludwiguer answered , you need to log it with ```useEffect```. This question is answered alot of times on stack already. – CevaComic Jun 18 '20 at 21:50
  • 1
    Does this answer your question? [useState set method not reflecting change immediately](https://stackoverflow.com/questions/54069253/usestate-set-method-not-reflecting-change-immediately) – Samuel Goldenbaum Jun 18 '20 at 21:51
  • i understand what was answered in that question and i have also used the `useEffect` hook but it seems like my code doesn't just want to work and it seems like the state is not updating at all because the `useEffect` hook is not firing – lcl code base Jun 18 '20 at 22:03

3 Answers3

1

Since setState is async you will need to observe when it finishes, this can be easily done using useEffect and adding caritems to the dependencies array

const [cartitems, cartitemsfunc] = useState('');

const d = async () => {
  let items = await AsyncStorage.getItem('items');
  console.log('items from cart:' + items);
  cartitemsfunc(items);
};

useEffect(()=> {
 console.log('items from cart2:' + cartitems);
}, [caritems]);

d();
ludwiguer
  • 2,177
  • 2
  • 15
  • 21
1

As mentioned in the comments and link supplied, useState is asynchronous so setting a value and immediately reading it in the following line will not yield consistent result:

cartitemsfunc(items); // async call
console.log('items from cart2:' + cartitems); // cartitems not updated yet

It is important to also understand that whenever you update state using useState, the component will render again. If you have a method call in the body of the app it will be run everytime you update state. So what you have is a scenario where you are making a call to update state, but the method is being executed and ends up overwriting your changes.

const d = async () => {
let items = await AsyncStorage.getItem('items');
console.log('items from cart:' + items);
cartitemsfunc(items);
console.log('items from cart2:' + cartitems);
 };

d(); // this will run every time the component renders - after you update state

If you only need the value at initial render, then call the method from useEffect and set the dependency chain to [] so it only runs once at first render, and not every time state is updated.

Below is an example that demonstrates getting/setting values from localStorage and also updating the state directly.

CodeSandbox Demo

import React, { useState, useEffect } from "react";
import AsyncStorage from "@react-native-community/async-storage";
import "./styles.css";

export default function App() {
  const [cartItems, setCartItems] = useState(null);

  const setLSItems = async () => {
    await AsyncStorage.setItem(
      "items",
      JSON.stringify([{ id: "foo", quantity: 1 }, { id: "bar", quantity: 2 }])
    );

    getLSItems(); // or setCartItems("Foo");
  };

  const clearLSItems = async () => {
    await AsyncStorage.removeItem("items");

    getLSItems(); // or or setCartItems(null);
  };

  const getLSItems = async () => {
    const items = await AsyncStorage.getItem("items");

    setCartItems(JSON.parse(items));
  };

  // bypass using local storage
  const setCartItemsDirectly = () => {
    setCartItems([{ id: "baz", quantity: 3 }]);
  };

  useEffect(() => {
    getLSItems();
  }, []); // run once at start

  return (
    <div className="App">
      <div>
        <button onClick={setLSItems}>Set LS Items</button>
        <button onClick={clearLSItems}>Clear LS Items</button>
      </div>
      <div>
        <button onClick={setCartItemsDirectly}>Set Cart Items Directly</button>
      </div>
      <hr />
      {cartItems &&
        cartItems.map((item, index) => (
          <div key={index}>
            item: {item.id} | quantity: {item.quantity}
          </div>
        ))}
    </div>
  );
}
Samuel Goldenbaum
  • 18,391
  • 17
  • 66
  • 104
  • it works but once i get an error and it reloads it stops working, i think that's a different problem all together – lcl code base Jun 19 '20 at 20:48
  • your code gets an error - or you are seeing that on the sandcodebox demo? – Samuel Goldenbaum Jun 19 '20 at 21:09
  • my code is getting the error but its working i don't know if there is a way to hide the error in react native like how in a web application an error can be showing but the codes still runs – lcl code base Jun 19 '20 at 22:30
  • 1
    so finally it has been solved added a try catch statement and it hid the error and now everything is OK thanks a lot @samuel G – lcl code base Jun 19 '20 at 23:46
0

I think here console.log() statement is executed before updating the state. As here await has been used so it will execute the next lines before getting the result.

Therefore , in this type of situation we use combination of useEffect() and useState(). useEffect() for getting the data and useState() for updating the state and re-render the UI.

Dev Gorai
  • 1
  • 1