我正在实现一个使用 Json 生成的表单。从 API 中检索 Json,然后在我呈现输入元素的项目上循环。这是示例 Json:
{
name: {
elementType: 'input',
label: 'Name',
elementConfig: {
type: 'text',
placeholder: 'Enter name'
},
value: '',
validation: {
required: true
},
valid: false,
touched: false
}
}
这是我渲染表单的方式:
render() {
const formElementsArray = [];
for (const key in this.props.deviceConfig.sensorForm) {
formElementsArray.push({
id: key,
config: this.props.deviceConfig.sensorForm[key]
});
const itemPerRow = 4;
const rows = [
...Array(Math.ceil(props.formElementsArray.length / itemPerRow))
];
const formElementRows = rows.map((row, idx) =>
props.formElementsArray.slice(
idx * itemPerRow,
idx * itemPerRow + itemPerRow
)
);
const content = formElementRows.map((row, idx) => (
<div className='row' key={idx}>
{row.map((formElement) => (
<div className='col-md-3' key={formElement.id}>
<Input
key={formElement.id}
elementType={formElement.config.elementType}
elementConfig={formElement.config.elementConfig}
value={formElement.config.value}
invalid={!formElement.config.valid}
shouldValidate={formElement.config.validation}
touched={formElement.config.touched}
label={formElement.config.label}
handleChange={(event) => props.changed(event, formElement.id)}
/>
</div>
))}
</div>
...
}
我将表单状态存储在 redux 中,每次输入更改时,我都会更新状态。现在的问题是每次我更新状态时,整个表单都会再次重新渲染......有没有办法优化它,只重新渲染更新的表单元素?
编辑:
我在 React.memo
中使用了 Input.js
作为:
export default React.memo(input);
我的有状态组件是纯组件。
Parent 是类组件。
编辑2:
这是我创建 formElementArray
的方法:
const formElementsArray = [];
for (const key in this.props.deviceConfig.sensorForm) {
formElementsArray.push({
id: key,
config: this.props.deviceConfig.sensorForm[key]
});
答案 0 :(得分:1)
您可以像这样将内容作为一个单独的组件。
并从父组件中移除 formElementsArray
道具。
export default function Content() {
const formElementRows = useForElementRows();
formElementRows.map((row, idx) => (
<Input
formId={formElement.id}
handleChange={props.changed}
/>
)
}
内部 Input.js
const handleInputChange = useCallback((event) => {
handleChange(event, formId);
}, [formId, handleChange]);
<input handleChange={handleInputChange} />
export default React.memo(Input)
这样您就可以有效地记住 handleChange
。它将使我们能够防止其他 <Input />
不必要的渲染。
通过这样做 forElementRows 更改不会导致其他组件的任何重新渲染。
答案 1 :(得分:1)
正如天宇所说,您可以尝试使用容器;您正在传递一个新的引用作为更改处理程序,这不仅会导致组件重新创建 jsx,还会导致虚拟 DOM 比较失败并且 React 将重新呈现所有输入。
您可以为 Input 创建一个容器,它是一个纯组件:
const InputContainer = React.memo(function InputContainer({
id,
elementType,
elementConfig,
value,
invalid,
shouldValidate,
touched,
label,
changed,
}) {
//create handler only on mount or when changed or id changes
const handleChange = React.useCallback(
(event) => changed(event, id),
[changed, id]
);
return (
<Input
elementType={elementType}
elementConfig={elementConfig}
value={value}
invalid={invalid}
shouldValidate={shouldValidate}
touched={touched}
label={label}
handleChange={handleChange}
/>
);
});
渲染您的 InputContainer 组件:
{row.map((formElement) => (
<div className="col-md-3" key={formElement.id}>
<InputContainer
key={formElement.id}
elementType={formElement.config.elementType}
elementConfig={formElement.config.elementConfig}
value={formElement.config.value}
invalid={!formElement.config.valid}
shouldValidate={formElement.config.validation}
touched={formElement.config.touched}
label={formElement.config.label}
//re rendering depends on the parent if it re creates
// changed or not
changed={props.changed}
/>
</div>
))}
答案 2 :(得分:0)
您必须按照一些步骤来停止重新渲染。为此,我们必须使用 useMemo()
钩子。
First Inside Input.jsx
像下面这样记住这个组件。
export default React.memo(Input);
然后在Content.jsx
里面,记住elementConfig
、shouldValidate
、handleChange
<的值/strong> 道具。因为这些 props 的值是对象类型(非原始/引用类型)。这就是为什么每次传递这些 props 时,即使它们的值相同(内存位置不同),它们也不等于之前传递给该 props 的值。
const elementConfig = useMemo(() => formElement.config.elementConfig, [formElement]);
const shouldValidate = useMemo(() => formElement.config.validation, [formElement]);
const handleChange = useCallback((event) => props.changed(event, formElement.id), [formElement]);
return <..>
<Input
elementConfig={elementConfig }
shouldValidate={elementConfig}
handleChange={handleChange}
/>
<../>
据我所知,这应该可行。让我知道它是否有帮助。谢谢兄弟。