我有一个包含多种表单的网页。下面是该结构的最小示例:
export default function Example() {
const [previousFormFetchedFromWeb, setPreviousFormFetchedFromWeb] = useState(
{}
);
const [formA, setFormA] = useState({});
const [formB, setFormB] = useState({});
const router = useRouter();
useEffect(() => {
fetchFormFromWeb(router.query.id).then((previousForm) => {
console.log("fetched info from web");
setPreviousFormFetchedFromWeb(previousForm);
setFormA(previousForm.formA);
setFormB(previousForm.formB);
});
},[router.isReady]);
return (
<>
<FormA form={formA} />
<FormB form={formB} />
</>
);
}
function FormA({ form }) {
return (
<input
type="text"
name="field1"
id="field1"
value={formA.field1}
onChange={(e) => {
setFormA(e.target.value);
}}
/>
);
}
function FormB({ form }) {
return (
<input
type="text"
name="field2"
id="field2"
value={formB.field2}
onChange={(e) => {
setFormB(e.target.value);
}}
/>
);
}
我认为这应该是我的表单页面的封装逻辑。问题是,当为任何形式的字段调用 onChange 事件时,所有表单都会重新呈现。我假设 setState 应该只重新渲染具有受影响依赖项更改的组件。我错过了什么吗?
每当<Example />
的状态更新时,<Example />
重新渲染,这反过来也会重新渲染<FormA />
和<FormB />
。这是意料之中的。
您应该考虑将React.memo()
用于FormA
和FormB
,如果您希望它们仅在传递给它们的道具更改时重新渲染。
组件中的任何状态更改Example
都会触发对其子组件的重新渲染(FormA
,FormB
)。如果你想避免这种情况。将FormA
包装并FormB
在 React.memo 中。这样您就可以防止不必要的重新渲染
export default function Example() {
const [previousFormFetchedFromWeb, setPreviousFormFetchedFromWeb] = useState(
{}
);
const [formA, setFormA] = useState({});
const [formB, setFormB] = useState({});
const router = useRouter();
useEffect(() => {
fetchFormFromWeb(router.query.id).then((previousForm) => {
console.log("fetched info from web");
setPreviousFormFetchedFromWeb(previousForm);
setFormA(previousForm.formA);
setFormB(previousForm.formB);
});
},[router.isReady]);
return (
<>
<MemFormA form={formA} />
<MemFormB form={formB} />
</>
);
}
const MemFormA = React.memo(function FormA({ form }) {
return (
<input
type="text"
name="field1"
id="field1"
value={formA.field1}
onChange={(e) => {
setFormA(e.target.value);
}}
/>
);
})
const MemFormB = React.memo(function FormB({ form }) {
return (
<input
type="text"
name="field2"
id="field2"
value={formB.field2}
onChange={(e) => {
setFormB(e.target.value);
}}
/>
);
})