首页 > 解决方案 > 对从子组件更改父组件状态而不重新渲染所有子组件的最佳实践做出反应?

问题描述

我有一个项目,我在其中显示包含文本字段中人员属性的卡片,用户可以编辑文本字段以直接更改该人的属性值。但是,每次他们编辑文本字段时,都会重新渲染所有卡片,从而减慢应用程序的速度。这是一个例子:

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”?

标签: javascriptreactjsperformancereact-hooksusecallback

解决方案


正如其他人已经说过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;
    })
}, []);

推荐阅读