skip to Main Content

I am currently making a shopify app for a contract and I encountered a problem in where I labeled an old array as what my current state is then I push an object into said array and then if I console log the new array it logs as 2 ( Which is the amount of items in it ) and when I console log my old array it logs as the old array with the new object and this will work with multiple function runs in a row. the same problem is happening with my remove function also

On both function running the new array makes the app crash and on add function I have tried to pull current state and the array in it and not my previous state array and on the remove function I have kept it as the previous state array and both of them still have the same problem

Expected result
newArr will be what oldArr was just with the object
{
newWarehouseCode: string
shopifyLocationId: ”
}
pushed into the old array at the end

const [inv, setInv] = useState({
  invSync: true,
  newWarehouseCode: "",
  d365WarehouseLink: [1],
  invSyncTiming: {
    0: true,
    1: true,
    2: true,
    3: true,
    4: true,
    5: true,
    6: true,
    7: true,
    8: true,
    9: true,
    10: true,
    11: true,
    12: true,
    13: true,
    14: true,
    15: true,
    16: true,
    17: true,
    18: true,
    19: true,
    20: true,
    21: true,
    22: true,
    23: true,
  },
});

function addNewWarehouse() {
  if (inv.d365WarehouseLink.indexOf(inv.newWarehouseCode) == -1) {
    return setInv((prevInv) => {
      const oldArr = inv.d365WarehouseLink;
      console.log(oldArr); // gives me what newArr should be
      const newArr = oldArr.push({
        warehouseCode: inv.newWarehouseCode,
        shopifyLocationId: "",
      });

      console.log(newArr); // is a number which is 2
      return {
        ...prevInv,
        d365WarehouseLink: oldArr,
      };
    });
  } else {
    return alert("Warehouse Already Exists");
  }
}

function removeWarehouse(i) {
  console.log(i);
  return setInv((prevInv) => {
    const oldArr = prevInv.d365WarehouseLink;
    const newArr = oldArr.splice(i, 1);
    console.log(newArr);
    return {
      ...prevInv,
      d365WarehouseLink: oldArr,
    };
  });
}

2

Answers


  1. newArr will always be the new length of the array.

    From Array.prototype.push()

    Return value

    The new length property of the object upon which the method was called.

    Other problems I see are

    1. Why initialise d365WarehouseLink as [1] when it appears you want an array of objects? Just set it to an empty array [] initially
    2. If you want to search by warehouse code and warehouseCode is a property of the objects in the array, you cannot use indexOf(). Use Array.prototype.some() instead or maintain a separate Set of codes. An even better option in my opinion would be to use an object or Map, keyed by the warehouse code.
    const [inv, setInv] = useState({
      invSync: true,
      newWarehouseCode: "",
      d365WarehouseLink: [], // empty array
      invSyncTiming: { ... },
    });
    
    const warehouseCodes = useMemo(
      () =>
        new Set(inv.d365WarehouseLink.map(({ warehouseCode }) => warehouseCode)),
      [inv],
    );
    
    function addNewWarehouse() {
      if (!warehouseCodes.has(inv.newWarehouseCode)) {
        setInv((prev) => ({
          ...prev,
          d365WarehouseLink: [
            ...prev.d365WarehouseLink,
            {
              warehouseCode: inv.newWarehouseCode,
              shopifyLocationId: "",
            },
          ],
        }));
      } else {
        alert("Warehouse Already Exists");
      }
    }
    
    function removeWarehouse(i) {
      setInv((prev) => ({
        ...prev,
        d365WarehouseLink: prev.d365WarehouseLink.toSpliced(i, 1),
      }));
    }
    
    Login or Signup to reply.
  2. In the function addNewWarehouse, you are using inv which is an immutable array

    const oldArr = inv.d365WarehouseLink;
    ...
    const newArr = oldArr.push({
        warehouseCode: inv.newWarehouseCode,
        shopifyLocationId: "",
      });
    

    Instead, use prevInv

    const oldArr = prevInv.d365WarehouseLink;
    ...
    const newArr = oldArr.push({
        warehouseCode: prevInv.newWarehouseCode,
        shopifyLocationId: "",
      });
    

    The function should look as below

    function addNewWarehouse() {
      if (inv.d365WarehouseLink.indexOf(inv.newWarehouseCode) == -1) {
        return setInv((prevInv) => {
          const oldArr = prevInv.d365WarehouseLink;
          console.log(oldArr); // gives me what newArr should be
          const newArr = oldArr.push({
            warehouseCode: prevInv.newWarehouseCode,
            shopifyLocationId: "",
          });
    
          console.log(newArr); // is a number which is 2
          return {
            ...prevInv,
            d365WarehouseLink: oldArr,
          };
        });
      } else {
        return alert("Warehouse Already Exists");
      }
    }
    

    Also Array.push returns the length of the array. See MDN Docs

    So in your case when you do

      const newArr = oldArr.push({
        warehouseCode: inv.newWarehouseCode,
        shopifyLocationId: "",
      });
    
      console.log(newArr); // is a number which is 2
    

    newArr variable will contain the length of oldArr after pushing the object.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search