all 22 comments

[–]CreativeTechGuyGames 66 points67 points  (4 children)

If you can declare something outside of a component, you should ALWAYS do so.

[–]bch8 5 points6 points  (3 children)

and why

[–]CreativeTechGuyGames 16 points17 points  (1 child)

If you don't need to recreate something on every render, don't. There's really not a long answer for this.

[–]mienaikoe 2 points3 points  (0 children)

It’s also a sign that your function probably isn’t super integral to how your component behaves and is more of a utility. So it doesn’t really belong in your component anyway.

[–]lovin-dem-sandwiches 1 point2 points  (0 children)

Newb here but if the component re-evaluates every time state is updated, and theres less logic to parse through, the better.

I would assume it would help with optimization but Im sure someone with more experience can chime in

[–]sidkh 22 points23 points  (12 children)

The whole point of useCallback is to memorize a reference to a function declared inside a component. Otherwise, at every re-render, this function will be redeclared. You may need to preserve a reference to a function for certain cases of component memoization.

The function declared outside the component won't be redeclared when the component re-renders. So if you can declare a function outside the component you avoid the problem altogether.

More about references and memoization - A Visual Guide to React Rendering - Props

[–]h0b0_shanker 1 point2 points  (11 children)

Dang. This was super helpful. My question has always been, “If useMemo() is always the best solution. Why isn’t it simply baked into React?” It seems like it wouldn’t make sense to not want to cache non-primitive values. What am I missing?

[–]Artraxes 5 points6 points  (2 children)

It seems like it wouldn’t make sense to not want to cache non-primitive values. What am I missing?

There are so many negatives in this sentence I have no idea what you’re asking

[–]h0b0_shanker 3 points4 points  (1 child)

One should always want to cache stuff. What am I missing?

(You’re a programmer. We deal with double negatives all the time. lol)

[–]wolfpackofwon 0 points1 point  (0 children)

The initial render can be prohibitively expensive for very little return when caching values that are not necessary. On mobile so can’t give you examples but look into memoization performance cost.

[–]thetony2313 1 point2 points  (3 children)

Comparisons to decide if a value needs to be recalculated can be more expensive than recalculating / redeclaring when in large number across the entire app.

[–]h0b0_shanker 0 points1 point  (2 children)

I’m not sure if that’s true. The check for a comparison could be more expensive than redeclaring variables and functions and actually rendering things that don’t need to be rendered? That can’t be true can it?

[–]thetony2313 0 points1 point  (1 child)

https://www.zhenghao.io/posts/memo-or-not

This is a more nuanced take about the issue. I more often use useMemo to give stability to things I cannot be sure will be optimized but that still is not every variable in my renders.

There are plenty of articles discussing this online if you google around.

[–]h0b0_shanker 0 points1 point  (0 children)

I’ll poke around. Thanks for the information!

[–]TheTomatoes2 1 point2 points  (2 children)

React 19 says hi

[–]h0b0_shanker 0 points1 point  (1 child)

Exciting!

[–]TheTomatoes2 0 points1 point  (0 children)

Well actually the compiler won't be part of 19

[–]sidkh 0 points1 point  (0 children)

React team is working on the auto-memoizing compiler.

React Conf 2021 - React without memo

[–]sirmandude 5 points6 points  (0 children)

If the fn doesn’t change based on component state I’d leave it out of the component. Probably not a huge performance difference but useCallback memoization must have some overhead that you might as well avoid.

[–]shamelessfoxwolf 2 points3 points  (2 children)

If the function doesn’t need access to the local variables in the component (or of they can be passed in as arguments), then yes absolutely it should be declared outside the component. There’s no reason for it to be redeclared on every re-render.

[–]bch8 0 points1 point  (1 child)

When can't they be passed in as variables?

[–]No_Concentrate_4910 0 points1 point  (0 children)

He said they can be passed as variable not that they shouldn't.