简体   繁体   English

State 在 React 中点击不更新

[英]State not updating on click in React

I need to update the player state on click (setPlayerState) but it's not being doing on time.我需要在点击 (setPlayerState) 时更新播放器 state,但它没有按时进行。 I mean, it updates later on, so I get the first state only after the second click when the state has changed again.我的意思是,它稍后会更新,所以当 state 再次更改时,我只有在第二次单击后才能获得第一个 state。 Does anyone know how to solve this?有谁知道如何解决这个问题?

  const [player, setPlayerState] = useState({
    name,
    assertions: 0,
    score: 0,
    gravatarEmail,
  });

  function handleClick({ target }) {
    const id = target.getAttribute('data-testid').includes('correct');
    let points = 0;
    if (id) {
      const level = questions[index].difficulty;
      if (level === 'hard') points = THREE;
      else if (level === 'medium') points = TWO;
      else points = ONE;
      setPlayerState({
        ...player,
        assertions: player.assertions + 1,
        score: player.score + (TEN + (timer * points)),
      });
    }
  }

Some points in your codes stand out您代码中的一些要点很突出

  • You reference index inside of your if(id)... conditional but index is not set.您在if(id)...条件中引用了index ,但未设置index
  • ONE , TWO , THREE , and TEN are not set. ONETWOTHREETEN未设置。
  • Question scoring logic is tangled with state update logic问题评分逻辑与state更新逻辑纠结

Here is a minimal complete example that fixes these things and shows a better way to write onClick .这是一个最小的完整示例,它修复了这些问题并展示了编写onClick的更好方法。 Run the code example and click the question buttons to see how assertions and score updates respectively.运行代码示例并单击问题按钮以查看assertionsscore分别如何更新。

 function App({ questions = [] }) { const [player, setPlayer] = React.useState({ name: "Hanna", assertions: 0, score: 0, }) function calcScore(difficulty) { switch (difficulty) { case "hard": return 3 case "medium": return 2 default: return 1 } } function onClick(question) { return event => { if (event.target.getAttribute("data-test-id").includes("correct")) setPlayer({...player, assertions: player.assertions + 1, score: player.score + calcScore(question.difficulty) }) }} return <div> {questions.map((q, key) => <button key={key} data-test-id="correct" onClick={onClick(q)}> {q.ask} </button> )} <pre>{JSON.stringify(player, null, 2)}</pre> </div> } const questions = [ { ask: "What is?", difficulty: "easy" }, { ask: "How come?", difficulty: "medium" }, { ask: "Seriously?", difficulty: "hard" } ] ReactDOM.render(<App questions={questions} />, document.querySelector("#app"))
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.14.0/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.14.0/umd/react-dom.production.min.js"></script> <div id="app"></div>

Add a click state and useEffect to respond to it's change.添加点击useEffect并使用 Effect 来响应它的变化。 It effectively forces two passes for the re-render.它有效地强制进行两次重新渲染。

Also try setPlayerState with previous value parameter ie setPlayerState(player => which sometimes helps when updates are not noticed.也可以尝试使用先前的值参数 setPlayerState,即setPlayerState(player =>这有时会在未注意到更新时提供帮助。

  const [player, setPlayerState] = useState({
    name,
    assertions: 0,
    score: 0,
    gravatarEmail,
  });

  const [clickTarget, setClickTarget] = useState(null)

  function handleClick({ target }) {
    setClickTarget(target )
  }

  useEffect(() => {
    if (!clickTarget) return

    const id = clickTarget.getAttribute('data-testid').includes('correct');
    let points = 0;
    if (id) {
      const level = questions[index].difficulty;

      points = (level === 'hard') ? THREE :
        (level === 'medium') ? TWO : ONE;

      setPlayerState(player => ({
        ...player,
        assertions: player.assertions + 1,
        score: player.score + (TEN + (timer * points)),
      }))
    }
    setClickTarget(null)
  }, [clickTarget])

You can try to replace setState function called with the below code block to make sure state updated:您可以尝试用以下代码块替换调用的setState function 以确保state已更新:

setPlayerState(s => ({
    ...s,
    assertions: s.assertions + 1,
    score: s.score + (TEN + (timer * points)),
}));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM