[英]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您代码中的一些要点很突出
index
inside of your if(id)...
conditional but index
is not set.if(id)...
条件中引用了index
,但未设置index
。ONE
, TWO
, THREE
, and TEN
are not set. ONE
、 TWO
、 THREE
和TEN
未设置。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.运行代码示例并单击问题按钮以查看
assertions
和score
分别如何更新。
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.