我有一个功能组件,可呈现简单子组件的集合。父组件具有更新状态的功能,并传递给子组件。由于一些性能问题,我决定将子组件变成纯组件,以减少重新渲染的数量。不幸的是,由于功能是在父功能组件中定义的,因此每当状态更新并重新渲染父功能时,都会重新定义该功能。这使子组件认为传递的函数是新函数,并且无条件地导致重新渲染。
我已经对这个问题有两种单独的解决方案,但我认为两者都不太雅致。
在我的第一个解决方案中,我将子组件变成了基于类的常规组件,并定义了一个自定义shouldComponentUpdate
来基本上只忽略函数prop。这不是理想的,因为此用例实际上应该由重组包中的PureComponent
或pure
处理。
在第二个解决方案中,我使父组件成为基于类的组件,并定义了要作为原型方法传递给我的函数。但是,我一直试图避开基于类的组件。
这是我想作为功能组件重新创建的基于类的代码:
class Parent extends Component {
state = {
children: [1, 2, 3, 4] // populated by an api normally
selectedChildren: []
};
handleChildClick = childId => {
// adds or removes childId from this.state.selectedChildren
// based on if it's already in the array or not
};
render() {
const children = this.state.children.map((child) => (
<Child
key={child}
id={child}
onClick={this.handleChildClick}
selected={this.state.selectedChildren.includes(child)}
/>
))
return (
<div>
{children}
</div>
);
}
}
我想知道是否存在与上述代码等效的功能组件,请记住,子代是纯组件,仅当传递给它们的道具发生更改时才应重新渲染。
事实证明,有一个名为useCallback的钩子,可用于在将该函数传递给子组件之前对其进行记忆。由于该函数已被记忆,因此如果函数不变,则相等比较将返回true。问题中的代码将像这样被简单地重写:
const Parent = () => {
const [children, setChildren] = useState([1, 2, 3, 4])
const [selectedChildren, setSelectedChildren] = useState([])
const handleChildClick = useCallback(
childId => {
// adds or removes childId from selectedChildren state
// based on if it's already in the array or not
},
[]
)
const childComponents = children.map((child) => (
<Child
key={child}
id={child}
onClick={handleChildClick}
selected={selectedChildren.includes(child)}
/>
))
return (
<div>
{childComponents}
</div>
);
}