Reactjs 如何在不触发React中的子级重新呈现的情况下在父级中设置状态?
我有一个React web应用程序,可以有效地回答大量问题。这些问题需要根据各自的状态值(即:必须是数字字段中的数字)以及彼此的值进行验证/布局。一些更复杂的“验证”示例:Reactjs 如何在不触发React中的子级重新呈现的情况下在父级中设置状态?,reactjs,Reactjs,我有一个React web应用程序,可以有效地回答大量问题。这些问题需要根据各自的状态值(即:必须是数字字段中的数字)以及彼此的值进行验证/布局。一些更复杂的“验证”示例: 在允许“保存”按钮之前,问题A、B和C可能需要具有非空值 问题B的允许值范围可能取决于问题A的值 只有当问题A设置为“真”时,问题C才会显示 你可以想象许多其他的互动。该应用程序有数百个问题——因此,我在JSON对象中有它们的配置,如下所示: { id: 'version', required: true, label:
- 在允许“保存”按钮之前,问题A、B和C可能需要具有非空值
- 问题B的允许值范围可能取决于问题A的值
- 只有当问题A设置为“真”时,问题C才会显示
{ id: 'version', required: true, label: 'Software Version', xs: 3 },
{
id: 'licenseType', label: 'License Type', xs: 2,
select: {
[DICTIONARY.FREEWARE]: DICTIONARY.FREEWARE,
[DICTIONARY.CENTER_LICENSE]: DICTIONARY.CENTER_LICENSE,
[DICTIONARY.ENTERPRISE_LICENSE]: DICTIONARY.ENTERPRISE_LICENSE
}
},
... etc.
function Question(props) {
const { qConfig, valueChangedListener, defaultValue } = props;
const [value, setValue] = useState(props);
useEffect(() => {
if (qConfig.value && typeof defaultValue !== 'undefined') {
setValue(qConfig.value);
}
}, [qConfig.value])
const handleValueChange = (evt, id) => {
setValue(evt.target.value);
valueChangedListener(evt.target.value, id)
}
return <div style={{ maxWidth: '100%' }}>
<TextField
// various other params unrelated...
value={value ? value : ''}
onChange={(evt) => handleValueChange(evt, qConfig.id)}
>
// code to handle 'select' questions.
</TextField>
</div>
}
然后,我将使用FormPage
组件中的一个映射,将这个对象转换为实际问题,该组件是所有问题的父级。考虑到需要将这些交互存储在最接近的公共父对象中,我将所有问题
值存储在formData
状态变量对象中,FormPage
如下所示:
function FormPage(props) {
const [formData, setFormData] = useState(BLANK_REQUEST.asSubmitted);
const handleValueChange = (evt, id) => {
setFormData({ ...formData, [id]: evt.target.value})
}
return <div>
{QUESTIONS_CONFIG.map(qConfig => <Question qConfig={qConfig} value={formData[qConfig.id]} handleValueChange={handleValueChange}/>)}
// other stuff too
</div>
}
值得注意的是,现在,当它的值更改时,它只存储它自己的值,让FormPage
知道它的值已更新,以便FormPage
可以执行一些多问题验证
为了完成此操作,我在FormPage
上添加了一个回调函数:
const processValueChange = (value, id) => {
setFormData({ ...formData, [id]: value })
};
然后保留我的useEffect,它基于formData进行交叉问题验证:
useEffect(() => { // validation is actually bigger than this, but this is a good example
let missingArr = requiredFields.filter(requiredID => !formData[requiredID]);
setDisabledReason(missingArr.length ? "Required fields (" + missingArr.join(", ") + ") must be filled out" : '');
}, [formData, requiredFields]);
从FormPage
返回的内容对此有一个微小的更改:
return <div>
{questionConfiguration.map(qConfig =>
<Question
qConfig={qConfig}
valueChangedListener={processValueChange}
/>
</ div>
)
}
但那没用
我的猜测是,即使formData
(FormPage
上的状态对象)没有在返回中使用。。。它的修改仍然会每次触发完全重新渲染
但是我需要存储孩子们的价值,这样我就可以用这些价值做一些事情
。。。但是如果我将子级的值存储在父级状态中,它会重新呈现所有内容,并且速度慢得令人无法接受
我不知道怎么解决这个问题?帮忙
功能组件如何存储其子组件的所有值(用于验证、布局等)。。。在每次修改所述数据时不触发重新渲染?(我只希望在验证/布局函数发现需要更改的内容时重新渲染)
编辑:
最小沙箱:
我在问题组件中有一个console.log,这样我们可以看到它们何时呈现。很可能是
usemo
和useCallback
的组合。很难说没有一个我将如何快速构建一个代码沙盒。。。
const processValueChange = React.useCallback((value, id) => {
setFormData({ ...formData, [id]: value })
}
},[]);