1

I'm using ireact set state and trying to post data to my object that is nested with arrays.

Here is my default state:

 const [data, setData] = useState({
    working_hours: [
      {
        id: '',
        description: '',
        hours: '',
        price: '',
        total: '',
      },
    ],
    parts: [
      {
        id: '',
        description: '',
        unit: '',
        quanity: '',
        price: '',
        total: '',
      },
    ],
    other: [
      {
        id: '',
        description: '',
        quanity: '',
        price: '',
        total: '',
      },
    ],
  });

So what I want to do is for example push an object to they array working_hours and I don't know how to do it.

Here is my try:

 const handleAdd = () => {
    const test = {
      id: 3,
      description: 'This is a description',
      hours: 4.2,
      price: 500,
      total: 4421,
    };
    setData({ ...data, working_hours: test });
  };

But this is removing the last state and only replacing the first item.

modih65067
  • 109
  • 1
  • 6

3 Answers3

1

Let us see how your code is working. You have an object which has three attributes working_hours , parts and others (which are all arrays).

Now when you write setData({ ...data, working_hours: test });, what is happening behind the scene is, first you copy all the attributes of data into a new object, then the attribute working_hours is replaced by test.

However, what you really want is to append test to data.working_hours. This is how you do it setData({...data, working_hours:[...data.working_hours, test])

What happens here is, first, a new object is made with all the attributes of the object data. Then a new array is made, which has all the elements of data.working_hours (previous state's working_hours) and test. This array is assigned to working_hours attribute of the new object, and finally this state is assigned to the new object.

  • I got this error message @Shubham `data.working_hours is not iterable` – modih65067 Feb 05 '22 at 21:14
  • @modih65067 Are you sure about your default state? As described in the questions, `data.working_hours` is an array of objects. The error that you are getting happens when you use the spread operator on an object. Please reconfirm your default state. – Shubham Shukla Feb 06 '22 at 05:53
  • @modih65067 yes that is the default state, i replaced the state again in the question please check, I don't see any difference – modih65067 Feb 06 '22 at 08:19
0

You're not far off, but you need to copy both the outer object and the array you're pushing to. It's also important to use the callback form because you're updating state based on existing state, so you want to be sure you have the most up-to-date state:

const handleAdd = () => {
    setData(data => {
        const test = {
            id: 3,
            description: 'This is a description',
            hours: 4.2,
            price: 500,
            total: 4421,
        };
        return {
            ...data,
            working_hours: [...data.working_hours, test]
        };
    });
};
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • This solution doesn't work, but thank you for giving your two cents in, the error message i got is this: `react-dom.development.js:11633 Uncaught TypeError: data.working_hours is not iterable` – modih65067 Feb 05 '22 at 21:23
  • @modih65067 - This *does* work, with what you've shown in the question, which is that `working_hours` is an array. Arrays are iterable. So apparently, your data **isn't** what you've shown in the question. Remember, all we have when we're trying to help you is what you show us. Apparently, sometimes `working_hours` isn't the array you've shown. FWIW, having state data that changes shape is poor practice. – T.J. Crowder Feb 06 '22 at 10:29
0

This should work

const handleAdd = () => {
    const test = {
      id: 3,
      description: 'This is a description',
      hours: 4.2,
      price: 500,
      total: 4421,
    };
    const newData = {
      ...data,
      working_hours: [
        ...(data?.working_hours ? data.working_hours : {}),
        test
      ]
    };
    setData(newData);
};
Meddah Abdallah
  • 654
  • 1
  • 7
  • 25