NoobD0gg
NoobD0gg

Reputation: 30

React setState of Parent component without rerendering the Child

I have a parent Component with a state variable that gets changed by one of its child components upon interaction. The parent then also contains some more components based on the data in the state variable.

The problem is that the child component rerenders when the state of its parent changes because the reference to the setState function changes. But when I use useCallback (as suggested here), the state of my parent just does not update at all.

This is my current setup:

function ArtistGraphContainer() {

    const [artistPopUps, setArtistPopUps] = useState([])

    const addArtistPopUp = useCallback(
        (artistGeniusId, xPos, yPos) => {
            setArtistPopUps([{artistGeniusId, xPos, yPos}].concat(artistPopUps))
        },
        [],
    )


    return (
        <div className='artist-graph-container'>
            <ArtistGraph addArtistPopUp={addArtistPopUp} key={1}></ArtistGraph>
            {artistPopUps.map((popUp) => {
                <ArtistPopUp 
                    artistGeniusId={popUp.artistGeniusId}
                    xPos={popUp.xPos}
                    yPos={popUp.yPos}
                ></ArtistPopUp>
            })}
        </div>
    )
}

And the Child Component:

function ArtistGraph({addArtistPopUp}) {

    // querying data

    if(records) {

        // wrangling data

        const events = {
            doubleClick: function(event) {
                handleNodeClick(event)
            }
        }

        return (
            <div className='artist-graph'>
                <Graph
                    graph={graph}
                    options={options}
                    events={events}
                    key={uniqueId()}
                    > 
                </Graph>
            </div>
        )
    }
    else{
        return(<CircularProgress></CircularProgress>)
    }
}

function areEqual(prevProps, nextProps) {
    return true
}

export default React.memo(ArtistGraph, areEqual)

In any other case the rerendering of the Child component wouldn't be such a problem but sadly it causes the Graph to redraw.

So how do I manage to update the state of my parent Component without the Graph being redrawn?

Thanks in advance!

Upvotes: 1

Views: 1917

Answers (1)

Cory Harper
Cory Harper

Reputation: 1055

A few things, the child may be rerendering, but it's not for your stated reason. setState functions are guaranteed in their identity, they don't change just because of a rerender. That's why it's safe to exclude them from dependency arrays in useEffect, useMemo, and useCallback. If you want further evidence of this, you can check out this sandbox I set up: https://codesandbox.io/s/funny-carson-sip5x

In my example, you'll see that the parent components state is changed when you click the child's button, but that the console log that would fire if the child was rerendering is not logging.

Given the above, I'd back away from the usCallback approach you are using now. I'd say it's anti-pattern. As a word of warning though, your useCallback was missing a required dependency, artistPopUp.

From there it is hard to say what is causing your component to rerender because your examples are missing key information like where the graphs, options, or records values are coming from. One thing that could lead to unexpected rerenders is if you are causing full mounts and dismounts of the parent or child component at some point.

A last note, you definitely do not need to pass that second argument to React.memo.

Upvotes: 2

Related Questions