3

I have a react functional component that shows list of tags and posts + few static text/decorations. I store the currently selected tag in a state using useState hook. Posts are fetched by using apollo's useQuery hook with tag variable. User should able to select a tag and it will replace the current tag state - thus the useQuery(POSTS_QUERY) will re-run with new tag variable.

const onTagSelectChange = (window: Window, 
    router: NextRouter, 
    name: string, 
    checked: boolean,
    tagSetter: React.Dispatch<React.SetStateAction<string>>) => {

    if (checked) {
        setTagQueryInUrl(window, router, name)
        tagSetter(name)
    } else {
        setTagQueryInUrl(window, router, null)
        tagSetter(null)
    }
}

const NewsList: NextPage = () => {

    const router = useRouter()
    const query = router.query as Query

    // store tag in state
    // initialize tag from `tag` query
    const [tag, setTag] = useState(query.tag)

    const { data: postsData, loading: postsLoading, error: postsError } = useQuery(
        POSTS_QUERY,
        {
            variables: {
                tag: tag
            }
        }
    )

    const { data: tagsData, loading: tagsLoading, error: tagsError } = useQuery(TAGS_QUERY)

    // show error page if either posts or tags query returned error
    if (postsError || tagsError) {
        return <Error statusCode={500} />
    }

    return (
        <div>
            <h1>Here we have list of news, and I should not re-render everytim :(</h1>
            <Tags
                loading={tagsLoading} 
                data={tagsData} 
                isChecked={(name) => name === tag} 
                onChange={(name, checked) => onTagSelectChange(window, router, name, checked, setTag)}
            />
            <Posts loading={postsLoading} data={postsData} />
        </div>
    )
}

My question is, why is my h1 block keeps re-rendering even though I don't pass anything to it? Or do I completely misunderstand how react works?

Here I click on tags, and it shows h1 element keeps re-rendering

fullmoon6661
  • 101
  • 1
  • 10
  • 2
    You should inspect the elements panel to see if the `

    ` element is actually being changed. It's possible that the re-rendering you're seeing is because the siblings of the `

    ` element are being modified, thus their shared parent gets a reflow. You can also test this by moving `

    ` outside of the `
    ` so that it is no longer a sibling.

    – Wex Jan 17 '20 at 16:33
  • Does this answer your question? [Trace why a React component is re-rendering](https://stackoverflow.com/questions/41004631/trace-why-a-react-component-is-re-rendering) – Emile Bergeron Jan 17 '20 at 16:44
  • @EmileBergeron No, I'm not passing any props to the `

    ` element so that doesn't apply to my case.

    – fullmoon6661 Jan 17 '20 at 17:25
  • But the enclosing component re-renders, which includes all its children as well. – Emile Bergeron Jan 17 '20 at 17:28
  • @Wex I take a look at the inspector, and yes you are right the `

    ` isn't being modified. It looks like the `` is the one that's being modified, there is an `

    – fullmoon6661 Jan 17 '20 at 17:40

2 Answers2

3

React components re-render whenever their state or props change. If I am reading this correctly then you are changing tag in state whenever the url changes and thus making the component to re-render itself.

Vaintti
  • 166
  • 8
  • Yes, I'm changing my `tag` state in `onTagSelectChange`. But aren't other components that don't receive any props should not be re-rendered? – fullmoon6661 Jan 17 '20 at 17:23
1

As your state is declared on your NewsList component, any state change (as another user stated on his answer) will trigger a re-render of the whole component (NewList) and not only to the components that you have passed your state (thus to the static <h1> you have in there).

If there are parts of this component that have nothing to do with this state, you can move them outside to avoid the re-render.

Though, on cases like this, re-rendering your <h1> is not a cost for React. You should worry and follow this approach on custom components where more complex things going on (e.g. populating lists or calculating stuff etc..). In those cases, you don't want all this complex stuff to happen again, if they are not affected by a parent's state change. You should also always consider, if moving the component outside makes sense or by doing so, you make your code complex.

You should always strike a balance between well-organized and efficient code.

Michalis Garganourakis
  • 2,872
  • 1
  • 11
  • 24