React函数组件动态创建React.Dispatch及管控输入如何避免Hook报错
解决方案
错误原因
你遇到的报错是因为违反了React Hook的调用规则:useState 仅允许在函数组件的最顶层作用域调用,不能嵌套在回调函数、循环、条件分支中,你之前将useState写在addVal点击回调内,自然会触发规则报错。
实现方案
由于你无法单独封装列表项组件,我们可以将所有输入项的状态统一存在组件顶层的useState中,通过唯一标识匹配对应输入项做更新,完全适配Fluent UI的onRenderItemColumn使用场景:
import { useState, useCallback } from 'react'; interface InputItem { id: number; // 用唯一标识匹配对应输入项 value: string; } function MyReactFunction() { const [allVals, setAllVals] = useState<InputItem[]>([]); // 新增输入项 const addVal = useCallback(() => { setAllVals(prev => [ ...prev, { id: Date.now(), // 用时间戳作为简易唯一id,也可以用自增数字 value: '' } ]); }, []); // 更新指定输入项的值 const handleInputChange = useCallback((id: number, newValue: string) => { setAllVals(prev => prev.map(item => item.id === id ? {...item, value: newValue} : item ) ); }, []); // 提交时获取所有值 const handleSubmit = useCallback(() => { const valueList = allVals.map(item => item.value); // 后续处理提交逻辑 console.log(valueList); }, [allVals]); // 原生渲染示例,可直接替换为Fluent UI组件逻辑 return ( <div> <button type="button" onClick={addVal}>Add input</button> <ul> {allVals.map(item => ( <li key={item.id}> <input value={item.value} onChange={e => handleInputChange(item.id, e.target.value)} /> </li> ))} </ul> <button type="button" onClick={handleSubmit}>提交</button> </div> ); }
Fluent UI适配说明
如果你使用Fluent UI的DetailsList/List组件,只需将allVals作为items属性传递给组件,在onRenderItemColumn回调中直接拿到当前渲染的item对象,绑定value和onChange即可,无需自定义列表项组件:
import { DetailsList } from '@fluentui/react'; // 组件内return部分示例 return ( <div> <button type="button" onClick={addVal}>Add input</button> <DetailsList items={allVals} onRenderItemColumn={(item, _index, column) => { if (column?.key === 'inputColumn') { return ( <input value={item.value} onChange={e => handleInputChange(item.id, e.target.value)} /> ) } return null; }} columns={[ { key: 'inputColumn', name: '输入项', minWidth: 300 } ]} /> <button type="button" onClick={handleSubmit}>提交</button> </div> )
方案合规性说明
- 所有Hook均在组件顶层调用,不会触发Hook规则报错
- 满足你提出的所有需求:点击新增输入、输入内容正常回显、提交时可直接获取所有输入值组成的数组
- 配合
useCallback缓存函数引用,结合React的列表key优化,不会产生多余的DOM重渲染 - 无需封装单独的列表项组件,完全适配Fluent UI的
onRenderItemColumn使用逻辑
内容的提问来源于stack exchange,提问作者Brent
相关产品推荐
相关产品推荐

