简体   繁体   中英

spread operator not working in nested setState within useEffect using .map() function

  const [columns, setColumns] = useState({
    Configured: {
      progress: "Configured",
      tasks: [],
    },
    Approved: {
      progress: "Approved",
      tasks: [],
    },
    AwaitingPO: {
      progress: "Awaiting PO",
      tasks: [],
    },
    InProduction: {
      progress: "In-Production",
      tasks: [],
    },
    Delivered: {
      progress: "Delivered",
      tasks: [],
    },
  });

  const { loading, error, data } = useQuery(GET_CUSTOMERS);

  useEffect(() => {
    if (data) {
      data.customer.map((item) => {
        setColumns({
          ...columns,
          [item.progress]: {
            ...columns[item.progress],
            tasks: [
              ...columns[item.progress].tasks, ///Spread operator not working here
              item
            ],
          },
        });
      });
    }
  }, [data]);

I am trying to add several objects named item to my tasks array. Out of the three items I have, only one is being added. Nested states seems to be quite hard, and I feel like I'm doing something wrong regarding useEffect or the map function itself.

Your effect has a missing dependency of columns making columns a stale closure .

To prevent the dependency you can pass a callback to the state setter function. You are also using Array.prototype.map in a wrong way, you should be using Array.prototype.reduce:

useEffect(() => {
  setColumns((columns) =>
    data
      ? data.customer.reduce(
          (columns, item) => ({
            ...columns,
            [item.progress]: {
              ...columns[item.progress],
              tasks: [
                ...columns[item.progress].tasks,
                item,
              ],
            },
          }),
          columns
        )
      : columns
  );
}, [data]);

Because data is a useEffect object can not keep track of its internal changes because the comparison is by reference

you can do such

This is how you compare by the length of the object

React.useEffect(()=>{},[data.length])

Or alternatively, you can do so

React.useEffect(()=>{},[JSON.stringify(data)]

This way you turn it into a string and do not compare according to the reference

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM