Search code examples
reactjsarraysreact-hooksstatereact-functional-component

React_Access to state array


I need to update state of my array order conditionally (checking for duplicates), but can't access order values inside function addToBasket. At the same time it's updated and I have an access there in my first console.log (see the snippet below):

 const [order, setOrder] = useState<IGoodsCart[]>([]);
  console.log(order); **//1 visible**

  const addToBasket: AddToBasketFunc = (item) => {
    console.log(order); **//2 not visible**
    const itemIndex = order.findIndex((orderItem) => orderItem.id === item.id);
    if (itemIndex < 0) {
      const newItem = {
        ...item,
        quantity: 1,
      };
      setOrder((order) => [...order, newItem]);
    } else {
      const newOrder = order.map((orderItem, index) => {
        if (index === itemIndex) {
          return {
            ...orderItem,
            quantity: orderItem.quantity + 1,
          };
        } else {
          return orderItem;
        }
      });
      setOrder(newOrder);
    }
  };

What's the best way to manage with it?

I was thinking to use useRef hook, but hope that there is another best solution for this case.


Solution

  • It looks like you are calling your function before/after your state is updated. It's hard to tell without more code, but I can see two options.

    One is to pass the current order as a parameter to your function and provide it wherever you are using it. The second option is to move your logic into the updater function which will give you access to the current order as well.

    In my opinion, Option 1 would be a bit more optimal.

    Option 1.

    Here we add order as a parameter to your function and then you need to remember to pass it in places where you use your function:

      const [order, setOrder] = useState<IGoodsCart[]>([]);
    
      //...
    
      const addToBasket: AddToBasketFunc = (item, order) => { // added parameter
        const itemIndex = order.findIndex((orderItem) => orderItem.id === item.id);
        if (itemIndex < 0) {
          const newItem = {
            ...item,
            quantity: 1,
          };
          setOrder((order) => [...order, newItem]);
        } else {
          const newOrder = order.map((orderItem, index) => {
            if (index === itemIndex) {
              return {
                ...orderItem,
                quantity: orderItem.quantity + 1,
              };
            } else {
              return orderItem;
            }
          });
          setOrder(newOrder);
        }
      };
    
      //...
    
      addToBasket(item, order); // add this parameter wherever you call this function
    

    Option 2.

    Here we are making use of the current state which is provided in the updater function and doing more logic there:

    const [order, setOrder] = useState<IGoodsCart[]>([]);
    
    const addToBasket: AddToBasketFunc = (item) => {
      setOrder((order) => {
        const itemIndex = order.findIndex((orderItem) => orderItem.id === item.id);
        if (itemIndex < 0) {
          const newItem = {
            ...item,
            quantity: 1,
          };
          return [...order, newItem]; // update state
        } else {
          const newOrder = order.map((orderItem, index) => {
            if (index === itemIndex) {
              return {
                ...orderItem,
                quantity: orderItem.quantity + 1,
              };
            } else {
              return orderItem;
            }
          });
          return newOrder; // update state
        }
      });
    };