繁体   English   中英

从子组件更改父组件的 state 而不重新渲染所有子组件的最佳实践?

[英]React best practice for changing state of parent component from child without rerendering all children?

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

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};
}

所以本质上,当孩子的文本字段被更新时,它会在存储新值的父项中触发 state 更改,然后刷新孩子的样子。 用户没有点击按钮来“保存”这些值——一旦他们编辑了文本字段,它就是一个永久性的改变。 并且父级需要知道每个 Person 的新值,因为有些功能需要知道人员列表的当前 state。 Person 组件包含的图像如果处理效率低下会减慢渲染速度。

有没有更好的方法让这个设计更高效并减少重新渲染? 我试图使用 useCallback 来保留这些功能,但我在这个特定的设计中不起作用,因为属性和值不同——我是否必须为每个确切的属性创建一个新的“modifyPerson”?

使用React.memo()

React.Memo 将检查传递给组件的 props,只有当 props 发生变化时,它才会重新渲染该特定组件。

因此,如果您有多个Person组件正在获取对这些Person明确的道具,并且当您更改导致 Parent state 更新的特定Person组件时,只有您修改过的Person组件将重新渲染,因为它的道具将改变(假设您将更改后的值传递给它)。

其他组件将具有相同的道具并且不会改变。

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()是 go 的方式,但这仍然会重新渲染,因为您每次都重新创建modifyPerson 您可以使用useCallback始终获得与 function 相同的标识,但是对于您当前的实现,您必须将personList添加为依赖项,这样也不起作用。

setPersonList有一个技巧,它还接受一个 function,它采用当前的 state 并返回下一个 state。 这样modifyPerson不依赖于任何外部 scope (期望setPersonList通过反应保证始终具有相同的身份)并且只需要创建一次。

const modifyPerson = useCallback((index, property, value) {
    setPersonList(currentPersonList => {
        const newPersonList = _.cloneDeep(currentPersonList);
        newPersonList[index][property] = value;
        return newPersonList;
    })
}, []);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM