Lets say I have these two components:
const availableTasks = [1, 2, 3];
const Task = () => {
const [current, setCurrent] = React.useState(0);
const getNextTask = () => current + 1 < availableTasks.length ? current + 1 : 0;
return (
<div className='task-container'>
<div className='task-information'>
Some information.
</div>
<TaskVote id={availableTasks[current]} key={current}/>
<button onClick={() => setCurrent(getNextTask())}> Next Task</button>
</div>
);
};
const TaskVote = ({ id }) => {
const [count, setCount] = React.useState(0);
React.useEffect(() => {
setInterval(() => setCount(count => count + 1), 1000); // Async data receiving (e.g. websocket)
}, []);
return <div> Counting for: {id}, Counted: {count}</div>;
};
TaskVote
receives its data from websockets, and updates count
state when needed. (Replaced it with interval, for the example)
Task
renders some information about the task, it renders TaskVote
, and a "Next Task" button
.
When user is skipping to the next task, TaskVote
receives new key, so it will re-mount, which is fine.
In case there is only one element in availableTaks
, the key
prop won't change, so count
state will not reset, even though I want it to reset once the button is clicked (even if it's the same Task).
How can I handle this case?
Thanks!
Your problem is that you use a simple number as the key which does not update if your next task is the same as before.
This leads to the following rendering multiple times: <TaskVote id={1} key={0}/>
React cannot determine that something changed.
A simple solution is to keep a separate state which can be used as a key.
const [voteState, setVoteState] = useState(0)
...
<TaskVote id={availableTasks[current]} key={voteState}/>
<button onClick={() => {
setCurrent(getNextTask())
setVoteState((s) => s+1) // always increasing
}}> Next Task</button>
However, setting multiple state values can lead to multiple rerenders. You can optimize this by merging multiple values (or by useReducer):
const [current, setCurrent] = React.useState({ task: 0, voteButtonState: 0 });
...
<TaskVote id={availableTasks[current]} key={current.voteButtonState}/>
<button onClick={() => {
setCurrent((old) => {
return {
task: getNextTask(),
voteButtonState: old.voteButtonState + 1 // always increasing
}
})
}> Next Task</button>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.