0

I have an object that takes the following form:

booking Object {
  "2019-11-29": Object {
    "selected": true,
  },
  "2019-11-30": Object {
    "selected": true,
  },
}

that I want to modify through invoking a function. More specifically, I want to toggle the selected property, which is Boolean.

I want to invoke a function that 1) checks to see if a certain key exists in the object, "2019-11-29" in this example, and if it does, 2) toggle the selected property, while everything else in the object remain the same.

My following code toggles the selected property temporarily, but doesn't save it in the state.

    const [selected, setSelected] = useState([])    
    const [booking, setBooking] = useState({})    

    const select = day => {
        let markedDay = day.dateString

        // first checks in the "selected" array to see if the "markedDay" exists
        if(selected.includes(markedDay)){
            // toggles the property within the "booking" object
            booking[markedDay] = {
                selected: !booking[markedDay].selected
            }

            setBooking(booking) // this hook doesn't update the state with the newly toggled object property
        }

        // saves the "markedDay" into a new array if it doesn't exist in the array already
        const newSelected = [...selected, markedDay];

        // assigns the property "selected" to the newly entered date and combines it with the pre-existing object
        let obj = newSelected.reduce((c, v) => Object.assign(c, {
          [v]: {
            selected: true,
          }
        }), {})
        setSelected(newSelected)
        setBooking(obj);
    }

What I mean by temporarily is that when I console log the booking object right after the booking[markedDay].selected has been toggled, it will show that the property shows as false, which is the intended result. However, if I were to console log booking outside of the if statement, the global state still shows the property as true.

P.S. I have mistakenly named the array state selected of the useState the same as the property of the object selected, but they are unrelated.

Kevvv
  • 3,655
  • 10
  • 44
  • 90
  • Does this answer your question? [How to update nested state properties in React](https://stackoverflow.com/questions/43040721/how-to-update-nested-state-properties-in-react) – Emile Bergeron Nov 13 '19 at 19:25

1 Answers1

3

You're directly modifying the state, that's why the updates aren't reflected in the component. To achieve what you want you can use functional form of setState and object spread:

 if (selected.includes(markedDay)) {
   setBooking(currentBooking => {
     return {
       ...currentBooking,
       [markedDay]: {
         ...currentBooking[markedDay],
         selected: !currentBooking[markedDay].selected
       }
     }
   })
 }
Clarity
  • 10,730
  • 2
  • 25
  • 35
  • for some reason the property is still not being toggled. Should I be making use of `currentBooking` in the return? – Kevvv Nov 13 '19 at 20:06
  • Ah, my bad, of course it has to be `currentBooking` instead of `booking`. I've updated the answer. – Clarity Nov 13 '19 at 20:07
  • I'm not sure why, but it's still not toggling the boolean property. Console.logging `markedDay` and `currentBooking` show correct states, but console.logging `booking` still show the `selected` property as true – Kevvv Nov 13 '19 at 20:17
  • @Kevvv where are you logging those? – Clarity Nov 13 '19 at 20:19
  • inside the `if` statement for `currentBooking` and `markedDay` and outside for `booking` where the state is ultimately being used. – Kevvv Nov 13 '19 at 20:21
  • Hmm, isn't `selected` an array of objects? In that case `selected.includes(markedDay)` might not work. Try removing the condition and see if the value gets toggled. – Clarity Nov 13 '19 at 20:24
  • `selected` is just an array like `["2019-11-22", "2019-11-23"]`. The `if` condition is true for `selected.includes(markedDay)` when `markedDay` is passed more than once so the logic inside the `if` statement is being executed. – Kevvv Nov 13 '19 at 20:30
  • Then the code should work. Try checking the state values inside the render or do `useEffect(() => { console.log(booking)}, [booking])` to make sure you get the proper state value. – Clarity Nov 13 '19 at 20:47
  • had to put the rest of the code in the `else` statement. The rest portion of the code was overriding what was being done inside the `if` statement. Thank you for your help! – Kevvv Nov 13 '19 at 21:03