我的组件的结构是这样的。每个组件在自己的文件中都是自己的功能组件——这只是它们如何交互的示意图。
<FirstLevelComponent>
// propValue is declared on this level with useState hook.
<SecondLevelComponent someProp={propValue}>
<ChildComponent1></ChildComponent1>
<ChildComponent2 someProp={propValue}></ChildComponent2>
<ChildComponent3></ChildComponent3>
</SecondLevelComponent>
</FirstLevelComponent>
someProp
在FirstLevelComponent
中声明状态,并传递给SecondLevelComponent
,当它发生变化时,它触发整个SecondLevelComponent
的重新渲染。但是唯一依赖于这个道具的是其中一个孩子。其余孩子不受影响。
隔离该行为并仅将重新渲染范围限制为依赖该道具的单个子对象的最佳方法是什么?
一些约束条件:
- 这是一个巨大的生产应用程序,所以像
Just add redux
这样的东西不是一个简单的解决方案。 - 重构
SecondLevelComponent
将是一个挑战(1500行代码),虽然我对这样的机会持开放态度,但我正在寻找实现这一目标的方法,假设它不是一个hello world项目。在应用程序的早期阶段,简单而理想的解决方案在处理遗留代码时是相当重做的。
并且只将重新渲染的范围限制为依赖于该道具的单个子对象?
你想要完成的事情违背了React的本质。如果父组件有状态,并且该状态发生了变化,React将做出反应并重新呈现该组件。
当父组件的状态发生变化时,阻止其重新呈现是一种反模式(与使用useMemo
简单地阻止其子组件重新呈现相反)。
在我看来,你有以下选项:
- 为子组件添加状态。如果它是唯一依赖于此状态的组件,则应该进行简单的重构。
- 将父组件中的useState替换为useRef。将此传递给子进程以创建初始状态。
选项二可能会导致其他含义,如果应用中的其他任何东西都依赖于这段状态。
现在,如果你只是想让额外的孩子从重新渲染,这不是我上面引用的问题,你可以只是简单地使用useMemo
(和useCallback
如果传递一个函数作为道具)..
我看到了同样的问题,也是一个大应用
选项1
如果你可以将propValue
状态和ChildComponent2
组件移动到SecondLevelComponent
中,你可以利用React构图中的渲染
解释:在SecondLevelComponent的状态不会渲染他的孩子像ChildComponent1
和ChildComponent3
选项2
你可以使用React来记忆组件。使用ememo而不是React。注意,因为你没有像这样在ChildComponent1
和ChildComponent3
中传递propValue
:
// How to memoize
const ChildComponent1Memoized = React.useMemo(()=><ChildComponent1/>,[propValue])
// In this case ChildComponent1Memoized will not rerender again
<SecondLevelComponent someProp={propValue}>
{ChildComponent1Memoized} // <---
<ChildComponent2 someProp={propValue}></ChildComponent2>
<ChildComponent3></ChildComponent3>
</SecondLevelComponent>
额外如果你将函数作为道具传递,请确保在每个函数中使用useCallbak,因为它们在每次渲染中都在重建,这导致Memo不起作用