1

I have faced this problem in the past, an often times I'm not quite sure what solved it, or I need to go extremely out of my way just to update the state for the first time. Currently, I am working with a state that begins as an empty object...

// The Object for the Calendar
const [markedDateObjects, setMarkedDateObjects] = useState({})

I then have this state populated during a useEffect. It will run through an existing array, and for each element in this array, it will add a new key to the object.


// Sets the marked date objects
useEffect(() => {
    meetingDays.forEach(meeting => {
        console.log(meeting)
        setMarkedDateObjects({
            ...markedDateObjects, [meeting]: {marked: true, dotColor: COLORS.gradientColor1, color: 'rbga(255, 255, 255, .30)'}
        })
        console.log("Should change")
    })
    setLoading(false)
}, [meetingDays])


// Prints when marked date object is changed
useEffect(() => {
    console.log(markedDateObjects, "THIS IS STATE")
}, [markedDateObjects])

When the page is loaded, the terminal prints out...

 LOG  2022-09-12
 LOG  Should change
 LOG  2022-09-14
 LOG  Should change
 LOG  {"2022-09-14": {"color": "rbga(255, 255, 255, .30)", "dotColor": "#FFCB05", "marked": true}} THIS IS STATE
 LOG  {"2022-09-14": {"color": "rbga(255, 255, 255, .30)", "dotColor": "#FFCB05", "marked": true}} THIS IS STATE

This shows that it hits two dates, but only adds one to the state. It does not replace the first value, since there is no "THIS IS STATE" line printed beneath the first date. Does anyone understand what's going on here?

1 Answers1

2

Problem

markedDateObjects has the same value in each iteration, so only the last iteration really do something

Solution

Pass a function instead of a value

meetingDays.forEach(meeting => {
  setMarkedDateObjects(markedDateObjects => ({
    ...markedDateObjects, [meeting]: {marked: true, dotColor: COLORS.gradientColor1, color: 'rbga(255, 255, 255, .30)'}
  })
})

Gather the changes and set the state once

const newMarkedDateObjects = { ...markedDateObjects }
meetingDays.forEach(meeting => {
  newMarkedDateObjects[meeting] = {marked: true, dotColor: COLORS.gradientColor1, color: 'rbga(255, 255, 255, .30)'}
})
setMarkedDateObjects(newMarkedDateObjects)
Konrad
  • 21,590
  • 4
  • 28
  • 64
  • 2
    I think it would make more sense to gather all the changes up and then set the state once. – Etheryte Sep 09 '22 at 18:40
  • 1
    Fixed the syntax. Also, making the change once makes even more sense. – Konrad Sep 09 '22 at 18:41
  • I agree-- to be honest I was just doing it the way I was because I knew I'd end up facing this issue. Did not know that syntax, thank you! –  Sep 09 '22 at 18:42