// 意思是你永远不要写出下面这样的代码
const [userList, setUserList] = useState([]);
// ...
// 直接修改了上面通过 useState 返回的 userList
userList[idx].selected = !userList[idx].selected;
setUserList(userList);
可行的解决办法:
// 创建一个拷贝
let userListShell = [...userList]; // 或者 let userListShell = userList.map(shell => shell);
userListShell[idx].selected = !userListShell[idx].selected;
setUserList(userListShell);
Brief
最近在实现一个用户列表的全选功能,具体如下:
- 点击全选后所有用户前面的 checkbox(复选框)均变成选中状态,取消同理,所有在选中的 checkbox 变成未选中
- 当存在未选中状态的 checkbox 时,全选的 checkbox 需要变成未选中状态
export function Main() {
const [userList, setUserList] = useState([])
const [selectAll, setSelectAll] = useState(false)
const toggleAllSelections = () => {
// ①
let userListShell = [...userList]
userListShell.map(user => user.selected = !selectAll)
setSelectAll(!selectAll)
setUserList(userListShell)
}
return (
<div className='flex flex-col bg-white rounded shadow-sm'>
<div className='flex border border-gray-100 bg-[#f9fafb] h-14 items-center'>
<div className='flex ml-2 w-20'>
<input type='checkbox' className='mt-1.5 h-4 w-4' checked={selectAll}
onChange={() => toggleAllSelections()}/>
<label className='ml-1'>全选</label>
</div>
<Button content={<img src={ImageRefresh} alt='刷新'/>}></Button>
</div>
</div>
<div className='grow-0 flex flex-col overflow-auto max-h-156'>
{
userList.map((user, idx) => {
let key = user.name.toString() + ' : ' + user.selected.toString()
return (
<UserListItem key={key} user={user} onChange={() => {
// ②
let userListShell = [...userList]
userListShell[idx].selected = !userListShell[idx].selected
if (userListShell[idx].selected === false) {
setSelectAll(false)
} else if (userListShell.findIndex(user => user.selected === false) === -1) {
setSelectAll(true)
}
setUserList(userListShell)
}}/>
)
}
)
}
</div>
</div>
)
}
需要注意的是 ①,② 两处,在修改之前均按照开头给的方法进行了 state 的更新, 导致后面出现单个用户的复选框不能正常渲染的问题,但是在只修改 ② 的前提下,问题就得到了解决。 这在一定程度上说明单次直接使用 state 本身进行更新可能不会出现渲染的问题, 但是为了避免意料之外的情况,最好还是把 state 当初 readonly 变量进行处理。
Hint/Link
https://zh-hans.react.dev/learn/updating-objects-in-state#treat-state-as-read-only
有关操作 State 中的数组:https://zh-hans.react.dev/learn/updating-arrays-in-state