Search code examples
reactjsreact-nativereact-hooksasyncstorage

react native state not changing


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!!!


Solution

  • 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>
      );
    }