映射按钮的 useState

useState for mapped buttons

我有几张卡片是从 API 映射而来的。每张卡片都有一个按钮,单击该按钮会展开每张卡片的成绩部分。我的问题是,所有按钮只触发第一张卡片。

function showGrades() {
    let showAllGrades = document.getElementById('allGrades')
     
    if (showAllGrades.style.display === '' || showAllGrades.style.display === 'none') {
      showAllGrades.style.display = 'inline-block'
    } else {
      showAllGrades.style.display = 'none'
    } 
  }
 

  return (
    <>
      <Card className={"d-flex flex-row flex-wrap border-0"}>
        <Card.Img className='m-2' src={student.pic} style={{width:'8em', height:'8em', border:'1px solid black', borderRadius:'100px'}} />

        <Card.Body>
          <Card.Title as='h1'><strong>{student.firstName + ` ` + student.lastName}</strong></Card.Title>
              <span style={{float:'right'}}>
                <Button onClick={(e) => showGrades(e.target.id)} type='button' style={{background:'none', border:'none'}}>
                <i className='fa fa-plus' style={{fontSize:'24px', color:'#b2b2b2'}}></i>       
                </Button>
              </span>
          <Card.Text className="ps-4" as='p'>Email: {student.email}</Card.Text>
          <Card.Text className="ps-4" as='p'>Company: {student.company}</Card.Text>
          <Card.Text className="ps-4" as='p'>Skill: {student.skill}</Card.Text>
          <Card.Text className="ps-4" as='p'>Average: {student.grades.reduce((a, b) => a + parseFloat(b), 0) / student.grades.length}</Card.Text>
            <div id='allGrades' style={{paddingLeft:'1.5rem', display:'none'}}>
                      {student.grades.map((grade, index) => {
                        return (
                    <>
                    <div className='d-flex flex-column justify-content-center'>Test {index + 1} {grade}</div>
                    
                    </>
                  )
                })}
          </div>
          <span style={{paddingLeft:'1.5rem'}}>
            <Button type='button' className='bg-light' style={{color:'#000'}}>new tag</Button>
          </span>
        </Card.Body>
      </Card>
      
      
    </>
  )
}

沙盒以查看实际情况:https://codesandbox.io/s/optimistic-keldysh-9cqgxy?file=/src/App.js

谢谢

首先,要立即解决您的问题,您需要为每张卡使用唯一的 ID。通过创建唯一标识符后缀,可以避免 getElementById('allGrades').

的错误
function showGrades(indexFromParentMapping) {
  let showAllGrades = document.getElementById(
    `allGrades-${indexFromParentMapping}`
  );

 ...
}

一般来说,在 React 应用程序中使用 getElementById 是一种不好的做法,因为您已经可以访问特定元素而无需获取 ID,因为您在每张独立卡片上都有一个与按钮点击相关联的事件。考虑使用 react 来发挥你的优势,并将一个值传递给函数,你可以使用它来巧妙地访问存储在父级而不是子级中的更复杂的状态对象。

您的卡片渲染最终将如下所示,打开的功能和状态以及将上面分级的视图提升到父级:

 ...<div id={`allGrades-${props.index}`} ... />...

在此处阅读更多内容:https://reactjs.org/docs/lifting-state-up.html

打开控制台,你可以发现错误本身:)

您正在为多个 div 设置相同的 ID,这是不可能的,因为 ID 是唯一的。所以,除了first,其他节点都没有加入DOM.

你可以做的是,在设置 id 时,创建一个唯一的 id,也许 id = "allGraders"+some unique student id,然后在单击展开按钮时将该唯一的学生 id 作为参数传递给调用的函数。在那里搜索那个id

  const id = "allGrades" + id
    let showAllGrades = document.getElementById("allGrades");