Josh Comeau has a nice overview of useMemo and useCallback, one of my favourites: https://www.joshwcomeau.com/react/usememo-and-usecallback/#w...
It’s a great idea to decouple business logic from view logic, but then hooks are the wrong place to start. Last time I checked, you couldn’t use them at all outside of a React component. That’s just a terrible place to put your business logic if you want it to be isolated from the specifics of your view.
I’ve mostly moved away from React, so maybe this has changed recently, but it seems difficult considering the fundamentals of their design.
You don't always need this. Sometimes your business logic can just be a pure function. But where you do (and IME this is quite common), hooks are super nice.
However saying you only need those for performance reasons is wrong.
There are cases where avoiding re-rendering (thanks to useCallback) is avoiding an infinite loop.
I created a codesandbox[1] to illustrate this. Wrapping the "reset" function in a useCallback solves the infinite loop.
If your initial reaction is: "you should not create logic like this" or "you're adding unnecessary stuff" please note that this is a stripped down version of a real use case, where things make more sense.
The point is that it's hard to come up with a rule as to when to use useCallback. The best I can think about is: "if you don't have direct vision on where your function will be consumed, wrap it in useCallback". For example, when your function is defined and returned in a hook or defined in a parent component and given to children.
The point is that any of those children/consumers could have this function in a useEffect and so list it as a dependency of this useEffect.
[1]: Warning, clicking "Start" creates an infinite loop in your browser. https://codesandbox.io/s/intelligent-rgb-6nfrt3
There's no reason to reset before setting data again, and I'm not sure why you'd even consider putting the functions in the dependency array for the useEffect in usePets.
I can imagine reasons you'd want to setData in a useEffect (maybe when something else changes, or the user performs some interaction, you fetch new data and then set it), but the dependency would be the thing that indicates that action has happened, and not a reset function returned by a custom hook coupled with your data and setter function.
The point is not that this code is good or bad. It's that it is possible to write such hard to predict code.
Remember this is a stripped down version of some code running in production.
Now to address your specific points anyway: "There's no reason to reset again": in the non-stripped down version, the hooks rely on a third hook (let's call it "useToken") and needs to react accordingly to this change of token to fetch new data
"I'm not sure why you'd even consider putting the functions in the dependency array for the useEffect in usePets.": unfortunately react-hooks/exhaustive-deps is here to warn you. You can disable or ignore it but I guess you expose yourself to a real missing dependency? Genuinely very keen to hear if you use this rule in your projects and what you do in such cases (where you use a function in the useEffect but do not want to re-run the effect each time this fn changes). To me it's such a weird/unnatural thing to list functions as dependencies because almost all the time functions do not change.
> (The identity of the setCount function is guaranteed to be stable so it’s safe to omit.)
Maybe in JS it still warns in your example because setData is passed in from calling useResource, but at least with Typescript I'm pretty sure eslint infers this
How do you share data fetching logic across components
How do you share a common UI functionality like toggling states, starting timers, across components?
People are now more concerned about clearly writing business logic while stiching together React lifecycles methods, instead of the other way.
But there's another option: don't use React as a framework, use it as a library. And do your modules/components/reuse/fetching in your own plain code, while using React as a display layer. You don't even have to use React for the entire UI.
This is a silly argument to make. People don't want to onboard onto a myriad of little reinvented wheels just to put together a GUI. This is well known to be a major mistake, and the root cause of failure of countless projects.
People are paid to deliver features and fix bugs, and not to peruse through npm like they are playing Pokemon. React solves their problem by solving developers' problems. Don't you understand the value of using a standardized tool that answers all your problems?
Knowing how to architect your app remains important, and once you know it, it's trivial. For those who refuse to learn it because they deem it a gargantuan task, frameworks will keep trying to provide a "generic" solution, but a "generic" solution is by necessity overcomplicated, overengineered, and bloated, because it's trying to address EVERYONE's concern and specific needs.
At no point in time will a monolithic "everything solution" be simpler than a specific modular solution to a specific modular problem.
React started with the promise of simplicity, and being a library, not a framework. Somewhere along the line this ideal was lost, this happens often. And it happens often because many small elegant solutions start with the intent of replacing the status quo bloated behemoth framework that everyone hates. What they don't realize is that with lack of understanding of why frameworks end up like this, this is the fate THEY will share one day. Entropy is a b**ch.
Online forums dedicated to frameworks are filled with questions on what the framework does and how it works. No news there. What did you expect?
> Knowing how to architect your app remains important, and once you know it, it's trivial. For those who refuse to learn it because they deem it a gargantuan task, frameworks will keep trying to provide a "generic" solution, but a "generic" solution is by necessity overcomplicated, overengineered, and bloated, because it's trying to address EVERYONE's concern and specific needs.
I'm sorry, you typed a lot of words to actually say nothing. So you don't use all features provided by a tech stack. So what? That is not bloat. Writing software is not a game of bingo.
Also, reinventing the wheel when a fully working and tested wheel is already available is a very dumb mistake and a fundamental failure in the decision-making process.
> React started with the promise of simplicity, and being a library, not a framework. Somewhere along the line this ideal was lost, this happens often.
I don't think this is remotely true in any way. Undoubtedly React greatly simplifies the work of putting together working and full-featured SPAs. The concept is so good and so extensively proven that React is already being used to develop native GUIs in desktop applications.
Your comments reads as if you're tilting at a React windmill. It's ok if you like vanilla JavaScript, but you're not being honest with yourself if you're failing to understand what problems React solves, how well Reacts solves them, and why the whole world has basically standardized around it.
Interestingly enough, React is probably the only major frontend framework that is obsessive about backward compatibility.
I had to pull a component from an internal project into my codebase recently. The component was still class-based. Worked without a hitch in the modern hooks-only code base.
In other words, you're checking React discussions and finding discussions on how to maintain React code. What were you expecting to find?
> What happened with the simplicity of just "generate some boring ass HTML DOM in JSX, and it applies the diff to the actual DOM".
React happened, which does just that but transparently and effortlessly. In fact, React does it so well that a concern is to prevent it from applying those diffs when being updated when it doesn't need to.
> That's it. That's the entire value proposition of React and it needs no hooks, handles, states, immutables, events, data trees, properties, arguments, components, nothing else.
React does not need those features if you are using React for things other than developing graphical user interfaces, which by their very nature are stateful, emit and react to events, handle properties, etc.
There exist design choices that would end up with a different combo. Class components with hooks or function components using lifetime callbacks.
Yes, hooks — basically sub components with possible effects and yielding values, or DOM output — are a terrific idea and much more functional and principled than explicit lifetime callbacks.
All the dependency arrays and non-conditional checks etc are because of the function components approach and don’t have much to do with hooks.
I feel nearly every discussion on hooks mixes this up and makes the whole conversation just weird and confusing.
And because of React's design choices. Reactivity can be achieved without explicit dependency lists.