Reputation: 1962
I have the following simple component:
const Dashboard = () => {
const [{ data, loading, hasError, errors }] = useApiCall(true)
if (hasError) {
return null
}
return (
<Fragment>
<ActivityFeedTitle>
<ActivityFeed data={data} isLoading={loading} />
</Fragment>
)
}
export default Dashboard
I would like to prevent ALL re-renders of the ActivityFeedTitle
component, so that it only renders once, on load. My understanding is that I should be able to use the React.useMemo
hook with an empty dependencies array to achieve this. I changed by return
to be:
return (
<Fragment>
{React.useMemo(() => <ActivityFeedTitle>, [])}
<ActivityFeed data={data} isLoading={loading} />
</Fragment>
)
As far as I'm concerned, this should prevent all re-renders of that component? However, the ActivityFeedTitle
component still re-renders on every render of the Dashboard
component.
What am I missing?
EDIT:
Using React.memo
still causes the same issue. I tried memoizing my ActivityFeedTitle
component as follows:
const Memo = React.memo(() => (
<ActivityFeedTitle />
))
And then used it like this in my return:
return (
<Fragment>
{<Memo />}
<ActivityFeed data={data} isLoading={loading} />
</Fragment>
)
Same problem occurs. I also tried passing in () => false
the following as the second argument of React.memo
, but that also didn't work.
Upvotes: 8
Views: 16483
Reputation: 1
It's because rendering a parent causes it's children to re-render for the most part. The better optimization here would be to place your data fetching logic either in the ActivityFeed component or into a HOC that you wrap ActivityFeed in.
Upvotes: 0
Reputation: 11
The second argument passed to React.memo
would need to return true
in order to prevent a re-render. Rather than computing whether the component should update, it's determining whether the props being passed are equal.
Upvotes: 1
Reputation: 1720
You can use React.memo and use it where your define your component not where you are making an instance of the component, You can do this in your ActivityFeedTitle component as
const ActivityFeedTitle = React.memo(() => {
return (
//your return
)
})
Hope it helps
Upvotes: 1
Reputation: 12174
Use React.memo()
instead to memoized components based on props.
React.memo(function ActivityFeedTitle(props) {
return <span>{props.title}</span>
})
Take note:
This method only exists as a performance optimization. Do not rely on it to “prevent” a render, as this can lead to bugs.
Upvotes: 2
Reputation: 5786
Your usage of useMemo
is incorrect.
From react hooks doc:
Pass a “create” function and an array of dependencies. useMemo will only recompute the memoized value when one of the dependencies has changed. This optimization helps to avoid expensive calculations on every render.
If no array is provided, a new value will be computed on every render.
You need to use useMemo
like useEffect
here for computation of value rather than rendering the component.
React.memo
React.memo()
is the one you are looking for. It prevents re-rendering unless the props change.
Upvotes: 0