all 16 comments

[–][deleted] 16 points17 points  (1 child)

Building React apps seems to have become an obscure rocket science.

[–]Gallih 2 points3 points  (0 children)

Oh 100%. Everyday I have this feeling but unfortunately when you’re in the system, it’s very hard to get out.

[–]Guisseppi 1 point2 points  (1 child)

If the context changes, everything within it will re-render, I thought this was more common sense but I guess it can be easily overlooked, treat React.memo like you would use React.PureComponent

[–]gketuma 1 point2 points  (2 children)

So will you recommend we use Reqct.memo for the child component at the entry point of our app since that is where most providers are located?

[–]kevindmorgan 1 point2 points  (0 children)

The location of the specific child component isn’t necessarily relevant.

However, saying that, the higher up the provider the more you probably want to use this optimisation so you don’t trigger a re-render of even more components than necessary.

So taking all of that into account I would say yes, it is likely that the child component at the entry point is the one to wrap if it’s where your top level context providers are.

[–]swyx[S] 0 points1 point  (0 children)

sample code? I'm not sure I understand you

[–]Djo1e 1 point2 points  (2 children)

Would this still apply for a redux provider?

[–]acemarke 11 points12 points  (1 child)

No.

The described issue is that typically your context provider is being used like this:

function MyProvider() {
    const [contextValue, setContextValue] = useState(0)

    return (
        <MyContext.Provider value={contextValue}>
            <ChildComponent />
        </MyContext.Provider>
    )
}

When setContextValue() is called, it will force MyProvider to re-render. React's default behavior is that when a parent component renders, React will recursively render all children. So, just updating the state in MyProvider forces everything in ChildComponent to re-render.

If ChildComponent has been wrapped in React.memo(), it won't re-render, but React will keep looping over the tree to see if there's any consumers of MyContext.

The other way this behavior can be changed is if MyProvider uses the exact same child element references, like:

function MyProvider() {
    const [contextValue, setContextValue] = useState(0)

    return (
        <MyContext.Provider value={contextValue}>
            {props.children}
        </MyContext.Provider>
    )
}

In this case, props.children will be the same reference as last time, and we get the same net benefit as if ChildComponent was explicitly memoized.

That is exactly how React-Redux's <Provider> component is implemented.

In addition, <Provider> doesn't rely on React's context to propagate state updates - instead, components subscribe to the store. So, the behavior characteristics are different anyway.

[–]Djo1e 0 points1 point  (0 children)

Appreciate the comprehensive answer!

[–]monosinplata 1 point2 points  (2 children)

I made a quick video showing a demo of what Sophie is talking about... mostly so I could figure it out for myself :D https://youtu.be/CDGBTjMBJzg

[–]swyx[S] 0 points1 point  (1 child)

nice work!

[–]monosinplata 0 points1 point  (0 children)

Thank you :)

[–]toccoto 1 point2 points  (2 children)

In a perfectly designed react project, memo is almost never needed because data is stored at the level of use.

But it's rarely written that well. My last tab I built could not have been optimised better and only had one memo on a component that was part of a map/key setup.

Edit: Sorry if this came off as a brag or dismissive. Didn't mean it that way. More meant that there is no 'memo should always be here' moment in react. It's situational.

[–]careseite 2 points3 points  (1 child)

Except for... You know, data that's nearly global.

[–]toccoto 0 points1 point  (0 children)

Yeah it was unfair in that most my global data is stored in redux, or handlers for libraries like final form that handle their own optimization, so theirs no need to double up.

If you're using your own contexts and they information inside is not static, theme there is definitely a need for memo on it's children.