useState状态无法传入CustomHeader组件?技术问题求助
问题原因及解决方案
1. selectedColumn无法传入CustomHeader的原因
核心问题是闭包捕获旧值:
components通过useMemo(() => {}, [])创建,依赖数组为空,意味着这个对象只会在组件第一次渲染时生成,后续永远不会更新。- 第一次渲染时
CustomHeader捕获的selectedColumn是初始值null,哪怕外部通过setSelectedColumn更新了状态,CustomHeader因为是旧版本的组件实例,闭包里的selectedColumn永远停留在初始值,所以内部打印和状态判断都不会生效。 - 而
setSelectedColumn是useState返回的稳定函数(不会随组件渲染变化),所以点击事件能正常修改外部的状态。
2. 为什么必须用useMemo包裹components
AG Grid对传入的组件对象有缓存机制:
- 如果不用
useMemo,每次父组件渲染时,components都会被重新创建为一个新对象。 - AG Grid会检测到
agColumnHeader组件发生变化,随即销毁旧的列头组件、创建新的实例,这会导致组件频繁重建,出现渲染异常、状态丢失等问题,所以必须用useMemo缓存components,避免不必要的组件重建。
3. 内部用useState导致所有列头显示+的原因
每个CustomHeader都是独立的组件实例,各自维护自己的useState状态:
- 点击某列头时,只会触发当前组件实例的状态更新,显示+;其他列头的状态不会同步变化,所以之前点击的列头的+不会消失,最终所有点击过的列头都显示+。
修复方案
方案一:更新useMemo的依赖数组
把selectedColumn加入useMemo的依赖,这样当选中状态变化时,components会重新创建,CustomHeader会拿到最新的selectedColumn值:
const [selectedColumn, setSelectedColumn] = useState(null); console.log("selected Column Outside:", selectedColumn); const CustomHeader = (props) => { const colId = props.column.colId; console.log("selected Column In CustomHeader:", selectedColumn); return ( <div> <div style={{float: "left", margin: "0 0 0 3px"}} onClick={() => setSelectedColumn(colId)} > {props.displayName} </div> {selectedColumn === colId ? <FontAwesomeIcon icon={faPlus} /> : null} </div> ) } const components = useMemo(() => { return { agColumnHeader: CustomHeader } }, [selectedColumn]); // 添加selectedColumn作为依赖
方案二:通过AG Grid的Context传递状态(更推荐)
利用AG Grid的context机制传递状态,避免闭包问题,同时components的依赖可以保持为空:
const [selectedColumn, setSelectedColumn] = useState(null); console.log("selected Column Outside:", selectedColumn); // 配置AG Grid的context,传递最新状态 const gridOptions = useMemo(() => ({ context: { selectedColumn, setSelectedColumn } }), [selectedColumn]); const CustomHeader = (props) => { // 从context中获取最新的状态和更新函数 const { selectedColumn, setSelectedColumn } = props.context; const colId = props.column.colId; return ( <div> <div style={{float: "left", margin: "0 0 0 3px"}} onClick={() => setSelectedColumn(colId)} > {props.displayName} </div> {selectedColumn === colId ? <FontAwesomeIcon icon={faPlus} /> : null} </div> ) } const components = useMemo(() => { return { agColumnHeader: CustomHeader } }, []); // 依赖保持为空即可
内容的提问来源于stack exchange,提问作者Sweet Caramel
相关产品推荐
相关产品推荐

