My components are structured looks like this. Each component is it's own functional component in its own file - this is just a schematic of how they interract.
<FirstLevelComponent>
// propValue is declared on this level with useState hook.
<SecondLevelComponent someProp={propValue}>
<ChildComponent1></ChildComponent1>
<ChildComponent2 someProp={propValue}></ChildComponent2>
<ChildComponent3></ChildComponent3>
</SecondLevelComponent>
</FirstLevelComponent>
someProp
is declared in state in the FirstLevelComponent
and is passed along to the SecondLevelComponent
and when it changes, it triggers the re-render of the entire SecondLevelComponent
. But the only dependency on that prop is in one of the children. The rest of the children are unaffected.
What would be the best way to isolate that behavior and only limit scope of re-rendering to the single child that depends on that prop?
Some constraints:
- This is a huge production application so something like
Just add redux
would not be an easy solution. - Refactoring
SecondLevelComponent
will be a challenge (1500 lines of code), while I am open to such opportunity`, I am looking for the way to achieve this assuming it's not a hello world project. Solutions that are easy and ideal for application in its early stages are quite a rework when we are dealing with legacy code.
CodePudding user response:
and only limit scope of re-rendering to the single child that depends on that prop?
What you're looking to accomplish goes against the nature of React. If a parent component has state, and that state changes, React will react and rerender the component.
Stopping the parent component from rerendering when its state changes is an anti pattern (as opposed to simply stopping its children from rerendering with useMemo
).
The way I see it, you have the following options:
- Add state to the child component instead. If it's the only component reliant on this state, it should be a simple refactor.
- Replace useState with useRef in the parent component. Pass this to the child for creating initial state.
Option two could lead to other implications if anything else in the app is dependant on this piece of state.
Now, if you just want to keep the extra children from rerendering, which isn't exactly what I quoted above from the question, you could just simply use useMemo
(and useCallback
if passing a function as a prop)..
CodePudding user response:
I saw the same problem, also big application
Option 1
You can take advantage of render from React composition if you can move propValue
state and ChildComponent2
component into SecondLevelComponent
Explanation: the states in SecondLevelComponent wont rerender his childs like ChildComponent1
and ChildComponent3
Option 2
You can memoize you components using React.useMemo not React.memo because you are not passing propValue
in ChildComponent1
and ChildComponent3
like this:
// 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>
Extra
if you are passing functions as props be sure you are using useCallbak in every function, because they are rebuilding in every render, that cause Memo dosent work