将 React PureComponent 重构为基于钩子的功能组件



我有一个基于工人阶级的手风琴组件实现,我正在尝试重构它以使用新的钩子 api。

我的主要挑战是找到一种方法来仅重新渲染切换的<AccordionSection />,同时防止所有其他<AccordionSection/>组件在每次更新父<Accordion/>的状态(跟踪其状态上的打开部分)时重新渲染。

在基于类的实现中,我设法通过使<AccordionSection />成为PureComponent,通过利用contextAPI的高阶组件将isOpenonClick回调传递给它,并将这些回调保存在父<Accordion/>组件的状态上,如下所示:

this.state = {
/.../
onClick: this.onClick,
isOpen: this.isOpen
};

据我了解,它保留了对它们的引用,从而防止它们在每次<Accordion />更新时都创建为新实例。

但是,我似乎无法将其与基于钩子的实现一起使用。

我已经尝试过的一些事情没有成功:

  1. memo包装折叠折叠部分 - 包括第二个回调参数上的各种呈现条件。

  2. useCallback包装onClickisOpen回调(似乎不起作用,因为它们具有在每个<Accordion/>渲染时更新的依赖项)

  3. onClickisOpen保存为如下状态:const [callbacks] = useState({onClick, isOpen}),然后将callbacks对象作为ContextProvidervalue传递。(似乎错了,没有用)

以下是对我基于工作类的实现的引用:

https://codesandbox.io/s/4pyqoxoz9

和我的钩子重构尝试:

https://codesandbox.io/s/lxp8xz80z7

我将日志保留在<AccordionSection/>渲染上,以演示我试图阻止哪些重新渲染。

任何意见将不胜感激。

所以我在追了太多兔子之后最终添加了这个小金块。

const cache = {};
const AccordionSection = memo(({ children, sectionSlug, onClick, isOpen }) => {
if (cache[sectionSlug]) {
console.log({
children: children === cache[sectionSlug].children,
sectionSlug: sectionSlug === cache[sectionSlug].sectionSlug,
onClick: onClick === cache[sectionSlug].onClick,
isOpen: isOpen === cache[sectionSlug].isOpen
});
}
cache[sectionSlug] = { children, sectionSlug, onClick, isOpen };

这表明正在改变的是onClick。这似乎很明显,因为手风琴组件正在渲染和创建新onClick

useCallback包裹他onClick创造可以纠正这个问题。

const onClick = useCallback(
sectionSlug =>
setOpenSections({
...(exclusive ? {} : openSections),
[sectionSlug]: !openSections[sectionSlug]
}),
[]
);

虽然我似乎在这个过程中破坏了exclusive,因为它现在总是启用......

https://codesandbox.io/s/1o08p08m27

哦,我确实在那里移动了其他一些可能有助于修复的部分。

更新

重构以使用useReducer并将所有逻辑移动到那里,以便我们可以提供稳定的onClick

更新

他们说睡眠很好,但对我来说,这只是想入睡。

我知道我缺少一些东西......昨晚意识到我们不需要化简器,只需要setState的功能形式,它允许我们从useCallback记忆函数中访问最新状态。转换后的@itaydafna优化在这里 https://codesandbox.io/s/8490v55029

相关内容

  • 没有找到相关文章

最新更新