gpt4 book ai didi

reactjs - 当回调在父级中更改状态时,如何使用 React.memo 和 useCallback 优化 React 组件

转载 作者:行者123 更新时间:2023-12-03 14:02:45 25 4
gpt4 key购买 nike

我遇到了一个性能优化问题,我认为可以通过某种方式解决该问题,但我不确定如何解决。

假设我有一个想要可编辑的对象集合。父组件包含所有对象,并使用编辑器组件呈现一个列表,该组件显示值并允许修改对象。

一个简化的例子是这样的:

import React, { useState } from 'react'

const Input = props => {

const { value, onChange } = props

handleChange = e => {
onChange && onChange(e.target.value)
}

return (
<input value={value} onChange={handleChange} />
)
}

const ObjectEditor = props => {
const { object, onChange } = props

return (
<li>
<Input value={object.name} onChange={onChange('name')} />
</li>
)
}

const Objects = props => {

const { initialObjects } = props

const [objects, setObjects] = useState(initialObjects)

const handleObjectChange = id => key => value => {
const newObjects = objects.map(obj => {
if (obj.id === id) {
return {
...obj,
[key]: value
}
}
return obj
})
setObjects(newObjects)
}

return (
<ul>
{
objects.map(obj => (
<ObjectEditor key={obj.id} object={obj} onChange={handleObjectChange(obj.id)} />
))
}
</ul>
)
}

export default Objects

所以我可以使用React.memo,这样当我编辑一个对象的名称时,其他对象就不会重新渲染。但是,由于 onChange 处理程序每​​次都会在 ObjectEditor 的父组件中重新创建,因此所有对象始终都会呈现。

我无法通过在处理程序上使用 useCallback 来解决这个问题,因为我必须将我的 objects 作为依赖项传递给它,而每次对象的名称都会重新创建它变化。

在我看来,由于处理程序发生了变化,所有未更改的对象都没有必要重新渲染。应该有一种方法可以改进这一点。

有什么想法吗?

我在 React Sortly 存储库中看到,他们将 debounce 与每个对象编辑器结合使用来更改其自身状态。这仅允许编辑的组件在有人键入时进行更改和重新渲染,并且如果在给定延迟内没有其他更改事件出现,则仅更新父组件一次。

handleChangeName = (e) => {
this.setState({ name: e.target.value }, () => this.change());
}

change = debounce(() => {
const { index, onChange } = this.props;
const { name } = this.state;
onChange(index, { name });
}, 300);

这是我现在能看到的最好的解决方案,但由于他们使用 setState 回调函数,我无法找到一种方法来使其与钩子(Hook)一起工作。

最佳答案

您必须使用setState的函数形式:

setState((prevState) => {
// ACCESS prevState
return someNewState;
});

您将能够在更新时访问当前状态值 (prevState)。

这样您就可以使用 useCallback Hook ,而无需将状态对象添加到依赖项数组中。 setState 函数不需要位于依赖项数组中,因为它不会在渲染过程中发生更改。

因此,您将能够在子级上使用 React.memo,并且只有接收到不同 Prop (浅比较)的子级才会重新渲染。

下面片段中的示例

const InputField = React.memo((props) => {
console.log('Rendering InputField '+ props.index + '...');
return(
<div>
<input
type='text'
value={props.value}
onChange={()=>
props.handleChange(event.target.value,props.index)
}
/>
</div>
);
});

function App() {

console.log('Rendering App...');

const [inputValues,setInputValues] = React.useState(
['0','1','2']
);

const handleChange = React.useCallback((newValue,index)=>{
setInputValues((prevState)=>{
const aux = Array.from(prevState);
aux[index] = newValue;
return aux;
});
},[]);

const inputItems = inputValues.map((item,index) =>
<InputField
value={item}
index={index}
handleChange={handleChange}
/>
);

return(
<div>
{inputItems}
</div>
);
}



ReactDOM.render(<App/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"/>

关于reactjs - 当回调在父级中更改状态时,如何使用 React.memo 和 useCallback 优化 React 组件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57822144/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com