如何解决在不重新渲染所有子项的情况下,响应从子项更改父组件状态的最佳实践?
我有一个项目,我在文本字段中显示包含某人属性的卡片,用户可以编辑文本字段以直接更改该人的属性值。但是,每次他们编辑文本字段时,都会导致重新渲染所有卡片,从而降低应用程序的速度。下面是一个例子:
export default Parent() {
const [personList,setPersonList] = useState(/* list of person objects*/);
const modifyPerson(index,property,value) {
const newPersonList = _.cloneDeep(personList);
newPersonList[index][property] = value;
setPersonList(newPersonList);
}
const children = personList.map((person,index) => {
<Person
modifyPerson={modifyPerson}
index=index
/*properties on the person */
/>
});
return <div> {children} </div>
}
export default Person(props) {
const fields = /* assume a list of these textfields for each property */
<TextField
value={props.name}
onChange={(e) => modifyPerson(props.index,"name",e.target.value)}
value={props.name} >
return {fields};
}
因此本质上,当子项的文本字段更新时,它会触发存储新值的父项中的状态更改,然后刷新子项的外观。没有用户单击以“保存”值的按钮——一旦他们编辑了文本字段,它就是一个永久性的更改。并且父级还需要知道每个 Person 的新值,因为有些函数需要了解人员列表的当前状态。 Person 组件包含的图像会在效率低下时减慢渲染速度。
有没有更好的方法可以使此设计更高效并减少重新渲染?我尝试使用 useCallback 来保留函数,但我在这个特定的设计中不起作用,因为属性和值不同——我是否必须为每个确切的属性创建一个新的“modifyPerson”?
解决方法
React.Memo 将检查传递给组件的 props,只有当 props 发生变化时,它才会重新渲染该特定组件。
因此,如果您有多个 Person
组件正在获取这些 Person
明确的道具,并且当您更改导致父状态更新的特定 Person
组件时,只有您修改过的 Person
组件会重新渲染,因为它的 props 会发生变化(假设您将更改的值传递给它)。
其他组件将拥有相同的道具并且不会改变。
export default React.memo(Person(props) {
const fields = /* assume a list of these textfields for each property */
<TextField
value={props.name}
onChange={(e) => modifyPerson(props.index,"name",e.target.value)}
value={props.name} >
return {fields};
})
,
正如其他人已经说过的,React.memo()
是这里的方法,但这仍然会重新渲染,因为您每次都重新创建 modifyPerson
。您可以使用 useCallback
来始终获得相同的函数标识,但是对于您当前的实现,您必须将 personList
添加为依赖项,因此这也不起作用。
setPersonList
有一个技巧,它也接受一个函数,该函数接受当前状态并返回下一个状态。这样 modifyPerson
不依赖于任何外部作用域(期望 setPersonList
通过反应保证始终具有相同的标识)并且只需要创建一次。
const modifyPerson = useCallback((index,property,value) {
setPersonList(currentPersonList => {
const newPersonList = _.cloneDeep(currentPersonList);
newPersonList[index][property] = value;
return newPersonList;
})
},[]);
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。