They encapsulate logic so well and do an amazing job being this isolated data/event source.
I find that I reuse them far more than I reuse components.
They encapsulate logic so well and do an amazing job being this isolated data/event source.
I find that I reuse them far more than I reuse components.
* If there’s only useState, then everything is mostly fine. All is good.
* To avoid unnecessary re-rendering you’ll have to move callbacks into useCallback. These callbacks then also need to specify all of their dependencies. So many lines of code that are merely noise.
* They encourage having state locally in the component which often breaks down the moment you slightly tweak the design. So much refactoring!
* Dealing with any other (callback-based, stateful) API is confusing. If you want something to execute once initially you can use useEffect with an empty dependency list, but note that then there’s no way of accessing updates values (in callbacks) and everything will reflect the initial state. Often you’ll have to use useRef just to keep track of the current state. Or maybe useState?
* Debugging is painful. You forget one value in your dependency list and the weirdest things happen. Suddenly you have callbacks running in different rendering scopes with different values.
They feel very “brittle”: Once it works the code looks pretty, but when there’s a slight change of requirements you need to rethink everything.
I really like Vue 3’s Composition API as a much easier-to-use (IMO) implementation of hooks.
It’s conceptually very similar to React Hooks, but the method that defines them only runs once, when the component is instantiated. So straight away that removes any worries around conditionals and loops.
Instead of a plain value/object and an update function, the “hooks” instead return a reactive object that tracks it’s own dependencies (which are also all reactive objects). That removes any need to manage dependencies yourself, or for any memoization.
The only downside is that because a plain value (like a number or something) cannot be reactive, it has to be wrapped in an object and accessed via a “.value” property, but this is only relevant in the setup function. Anywhere else, like the Options API or in the template, accessing the value like a value will just get transparently proxied to the object.
- Agreed about useState (and useReducer). They’re simple and they get the job done.
- Agreed about useCallback as well, it’s a lot of boilerplate.
- State in general is a hard problem to deal with, but I’m not sure how hooks in particular encourage it? Class components had the same issue.
- IMO, useEffect is a huge footgun. I understand how it works, I understand how closures work, but it is by far the biggest source of hook-related bugs I’ve experienced.
- This eslint plug-in will solve your dependency list woes: https://www.npmjs.com/package/eslint-plugin-react-hooks
I'm not sure if I understood what you mean, but note that useState accepts not only the updated state, but also a function that takes the current state as argument and return the updated state.
In other words, instead of something like this
useEffect( async () => {
...
const someValue = await someFunction();
setState({...state, someValue });
}, [... ] );you should use something like this
useEffect( async () => {
...
const someValue = await someFunction();
setState( currentState => ({...currentState, someValue }));
}, [ ... ] );(the example is with async but it is the same for regular callbacks)
This should never happen. The only downside to hooks is that the eslint plugin is _required_, not optional. It is not worth the pain without it, but you'll be in a Whole New World once you do it. Since you can auto-fix every time, it'll become second nature and you'll never forget a dependency again. You can focus on getting your application to work.
This is what I hate in angular1 , there are at least 3-4 ways you can mess up a simple data-binding and there is no error or warning to inform you that something is not right so you waste a lot of time to figure it out.
I used react a few years back but it seems that this days it got hyper complex.
Don't you get eslint warnings right in your editor?
If you're using VS Code there's an extension for that...
This is by design. When you start making a component worry about what it needs to do on an update, rather than just rendering its data, you are introducing a whole new level of complexity. That's why class based React components could turn into these unwieldy confusing things where you never knew for certain what was going to render every time, because the shouldComponentUpdate method gets stuffed full of business logic.
Linters should help with missing dependencies.
I’m curious what you think of https://rxstore.dev/ it basically is a pattern I tried to outline where you write logic with rxjs and it tries to bridge the gap to react/hooks for you. I address some of your points in the faq.
There's an eslint plugin specifically for detecting this, which should probably be considered mandatory.
Really? I've been working with hooks for months, with code in production, and I hardly ever pass more than one or two items to the dependency list. The only time I really had any trouble with dependencies was when I was updating appContext inside a hook.
useEffect(() => {
const interval = setInterval(myFunc, 1000)
return () => clearInterval(myInterval)
},[])
I think one of the keys to React is not to fear the boilerplate.If you find yourself typing the same code too often, there’s probably a higher level abstraction that you should find, way above the level of setInterval.
I find coders often try to DRY up low level code to the detriment of actually dealing with their _application_ architecture.
In general, you should use the tools as provided, boilerplate and all, and then focus your real brain energies on the specific domain problems that only your application needs.
Creating thin wrappers on external tools to squeeze the last tiny bits of DRYness is not only usually a waste of time, but it makes your code unreadable. People know how setInterval and useEffect work. If I see useInterval I have to go read your code to know what’s happening. Especially if you made it configurable. And people _will_ tend to add configuration to these wrappers over time as needs change.
But they're also soooo idiosyncratic which makes them rather ugly on a general level.
But yes, insanely useful once you get the hang of them, they enable forms of abstraction and composability that you'll sorely miss when working in other UI frameworks.
You can definitely have "hooks" that are just normal js functions without limits.
My favourite public example of this is definitely solid.js (by ryansolid).
In general, I'm grateful to react / facebook for bringing in the spotlight the hyperscript way of doing applications and pushing tons of developers to develop similar libraries - but technically react is bloated and a ugly corporate mess.
Similar considerations for redux and elm.
You're no longer writing plain javascript, you're writing in some terribly verbose language where everything from variable declarations to function expressions needs to be wrapped, making it hard to integrate with this party APIs and small details can have a big impact on performance.
Both vue 3 and svelte show it can be done better.
There's something to having a function that can hold state or load its state on mount, etc.