[SOLVED] How to update only clicked element using useState?

Issue

I have a list of chapters that have a list of steps. I am trying to add a step to a chapter when clicking the button, but I am currently adding a step to all of the chapters instead.
What am I doing wrong?

  const dummy_chapters = [
    { id: 1, title: 'Chapter 1'},
    { id: 2, title: 'Chapter 2'},
    { id: 2, title: 'Chapter 3'},
  ]

const dummy_steps = [
    { id: 1, title: 'Step 1'},
    { id: 2, title: 'Step 2'},
  ]

  const [chapters, setChapters] = React.useState(dummy_chapters)
  const [steps, setSteps] = React.useState(dummy_steps)

  const addStep = () => {
    setSteps([
      ...steps,
      {
        id: 5,
        title: 'Another step'
      },
    ])
  }

  return (
      <List>
          {chapters.map((d, idx) => (
              <ChapterListItem    
                  secondaryAction={
                    <IconButton onClick={addStep}>
                      <MoreVertIcon/>
                    </IconButton>
                  }>
                  </ChapterListItem>
                <List component='div' disablePadding>
                  {steps?.map((d, idx) => (
                    <ListItemText primary={d.title}/>
                  ))} 
                </List> 
          ))}
      </List>
          <Icon onClick={addChapter} iconId='add' />
      </Box>
    </>
  )
}

Solution

Instead of managing chapters and steps differently you can add steps key inside of each chapters. Then for adding new steps you can try approach as mentioned below.

    const dummy_chapters = [{
        id: 1,
        title: 'Chapter 1',
        steps: [{
            id: 1,
            title: 'Step 1'
          },
          {
            id: 2,
            title: 'Step 2'
          },
        ]
      },
      {
        id: 2,
        title: 'Chapter 2',
        steps: []
      },
      {
        id: 2,
        title: 'Chapter 3',
        steps: []
      },
    ]

    const dummy_steps = [
        { id: 1, title: 'Another Chapter'},
      ]

     const [chapters, setChapters] = React.useState(dummy_chapters)

      const addStep = (chapterId) => {
        const updatedChapters = chapters?.map((chapter) => {
          if(chapter?.id === chapterId){
            chapter[steps] = [...chapter.steps, ...dummy_steps]
          }
          return chapter
        })
        setChapters(updatedChapters)
      }

      return (
          <List>
              {chapters.map((chapter, idx) => (
                  <ChapterListItem    
                      secondaryAction={
                        <IconButton onClick={() =>addStep(chapter?.id)}>
                          <MoreVertIcon/>
                        </IconButton>
                      }>
                      </ChapterListItem>
                    <List component='div' disablePadding>
                      {chapter?.steps?.map((step, idx) => (
                        <ListItemText primary={step.title}/>
                      ))} 
                    </List> 
              ))}
          </List>
              <Icon onClick={addChapter} iconId='add' />
          </Box>
        </>
      )
    }

Answered By – Sanket Shah

Answer Checked By – Marilyn (BugsFixing Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *