如何在React无限滚动表格中正确管理checkbox的选中状态
问题核心原因
当前实现存在两个核心问题:
- 直接将生成好的Checkbox组件存入
checkboxes状态,这些组件在创建时就固化了当时的isChecked属性值和onClick绑定的闭包值,后续父组件state更新时,这些已经存在状态里的旧组件不会自动更新props,所以既无法响应状态变化,点击也不会触发预期效果。 - useEffect的依赖数组不全,用到了
checkboxes、state等变量却没有加入依赖,会触发闭包陷阱,每次拿到的都是初始的旧值。
解决方案
不要把JSX组件存入状态,仅存储checkbox的id列表,渲染时动态遍历id列表生成组件,每次渲染都会从最新的state中读取选中状态,自然就能实现状态同步。
修改后可运行的index.js代码
import ReactDOM from "react-dom"; import "@elastic/eui/dist/eui_theme_amsterdam_light.css"; import React, { useState, useEffect } from "react"; import { EuiCheckbox, htmlIdGenerator } from "@elastic/eui"; import { arrayRange, getState } from "./utils"; const Checkbox = ({ id, isChecked, onClick }) => ( <div style={{ margin: "1rem" }}> <EuiCheckbox id={String(id)} // 直接用id作为唯一标识即可,不需要每次生成新的随机id label={isChecked ? `${id} - On` : `${id} - Off`} checked={isChecked} onChange={onClick} /> </div> ); const App = () => { const [state, setState] = useState(getState(0, 1)); // 仅存checkbox的id列表,不存组件 const [checkboxIds, setCheckboxIds] = useState(arrayRange(0, 1)); const [addMoreCheckboxes, setAddMoreCheckboxes] = useState(true); useEffect(() => { if (addMoreCheckboxes) { setAddMoreCheckboxes(false); setTimeout(() => { const start = checkboxIds.length; const end = start + 1; // 先更新选中状态 setState((prevState) => ({ ...prevState, ...getState(start, end) })); // 新增id到列表 setCheckboxIds(prev => prev.concat(arrayRange(start, end))); setAddMoreCheckboxes(true); }, 3000); } // 补充完整依赖 }, [addMoreCheckboxes, checkboxIds.length]); const handleClick = (id) => () => setState((prevState) => ({ ...prevState, [id]: !prevState[id] })); // 渲染时动态生成Checkbox组件 return <div style={{ margin: "5rem" }}> {checkboxIds.map(id => ( <Checkbox key={id} id={id} isChecked={state[id]} onClick={handleClick(id)} /> ))} </div>; }; ReactDOM.render(<App />, document.getElementById("root"));
utils.js的代码不需要修改,原有逻辑可以正常复用。
修改后所有checkbox都会实时绑定最新的state值,点击时也能正常触发状态更新,后续新增的checkbox也会自动继承这个逻辑,完全满足无限滚动表格的需求。
内容的提问来源于stack exchange,提问作者Jimmy
相关产品推荐
相关产品推荐

