Home > Mobile >  How to setState of an array of objects in functional components
How to setState of an array of objects in functional components

Time:10-12

I am trying to setState of an Array of objects when component load. state of the component is:

   const [weekdays, setWeekdays] = useState([{
    day: 'S',
    fullName: 'Sunday',
    select: false
},
{
    day: 'M',
    fullName: 'Monday',
    select: false
},
{
    day: 'T',
    fullName: 'Tuesday',
    select: false
},
{
    day: 'W',
    fullName: 'Wednesday',
    select: false
},
{
    day: 'T',
    fullName: 'Thursday',
    select: false
},
{
    day: 'F',
    fullName: 'Friday',
    select: false
},
{
    day: 'S',
    fullName: 'Saturday',
    select: false
}])

The array which I am trying to setState is: data

I am trying in this way to setState when page loads:

  useEffect(() => {
    {
        (data?.length > 0)
            ?
            setWeekdays([weekdays => (
                {
                    ...weekdays,
                    ...data?.map((item) => { return { day: item.day, fullName:item.fullName, select:true } }),
                })])
            :
            setWeekdays([...weekdays])
    }
}, [data]);

Thanks...

CodePudding user response:

These are two ways of solving this.

First one:

  • Following the approach for the weekdays and data structure you have in your question code - with each one as an array of objects:

       useEffect(() => {
           const newWeekdays = [];
           if (data?.length > 0) {
             setWeekdays((weekdays) => {
               for (const item in data) {
                 if (data[item] !== "") {
                   newWeekdays.push({ ...weekdays[item], select: true });
                 } else {
                   newWeekdays.push({ ...weekdays[item] });
                 }
               }
               return newWeekdays;
             });
           }
         }, [data]);
    

Second one: (which I think is better)

  • You can have the data as a simple array of indexes. This array will contain the indexes to the days objects that should be selected in the weekdays array. (You can leave the weekdays structure as it is in your question.)

    So now this how the data array looks like:

    const data = [0, 2, 4]; //Sunday, Tuesday, Thursday
    

    And this is how you can update the selected indexes to select:true :

    useEffect(() => {
        if (data?.length > 0) {
          setWeekdays((weekdays) => {
            const newWeekdays = weekdays.map((item, index) => {
              if (data.includes(index)) {
                return { ...item, select: true };
              }
              return { ...item };
            });
            return newWeekdays;
          });
        }
      }, [data]);
    

Hope this helps. Good luck!

CodePudding user response:

You created weekdays as an array, but when you call setWeekdays you are returning an object. You need to make sure your new value is the same structure.

That said, your current data structure is not very efficient. If I understand correctly, you simply want to store which set of days are selected. You would do better to have an object instead of an array.

const [weekdays, setWeekdays] = useState({
  sunday: {
    day: 'S',
    fullName: 'Sunday',
    select: false
  },
  monday: {
    day: 'M',
    fullName: 'Monday',
    select: false
  },
  tuesday: {
    day: 'T',
    fullName: 'Tuesday',
    select: false
  },
  wednesday: {
    day: 'W',
    fullName: 'Wednesday',
    select: false
  },
  thursday: {
    day: 'T',
    fullName: 'Thursday',
    select: false
  },
  friday: {
    day: 'F',
    fullName: 'Friday',
    select: false
  },
  saturday: {
    day: 'S',
    fullName: 'Saturday',
    select: false
  }
})
const data = ['monday', 'wednesday', 'friday']
useEffect(() => {
  setWeekdays(weekdays => ({
    ...weekdays,
    ...data
      .map(key => ({[key]: {...weekdays[key], selected: true}}))
      .reduce((prev, next) => Object.assign(prev, next))
  })
}, [data]);
  • Related