Since the introduction of Hooks, I've been struggling with understanding React and React code. For context: UI development is not my full-time job (anymore), and I mostly do backend dev these days. I still read/write React once in a while, but I don't enjoy it anymore.
Here is what I am struggling with: I am not able to grasp the programming model with Hooks. I am not able to read the code easily, nor am I able to easily understand the interactions in the app. "easily" being the keyword here. I can understand what is happening if I put in the effort, but every time, it is a struggle. I switch between languages and platforms all the time, but react code is where I have to take a real pause to understand what is going on.
My suspicion is that this has to do mostly with the names of the Hooks, and how they are used in the code.
* Why are they named useState, useEffect etc? Are there better names if used will make it easier for me to read this code? Are there any other systems/languages (even in JS) where similar constructs are present? What are their names?
* If JSX is anyway getting compiled to JS, why do I have to still deal with strange looking useState and useEffect declarations? Is there a way to get cleaner syntax and make React code read like regular code?
This is mostly a cry for help, and not a criticism of React. I have used React in the past (several years ago, before Hooks) and I used to "get" React.
terminology is one of the many funny things about React, in this release:
> By convention, functions that use async transitions are called “Actions”.
React is the only people who use this "convention". They pick a very meaningless word for their terminology, but then they just can't stick with it and have to name the hook `useTransition` for some reason.
Instead of wasting doc space for sentences like above, why don't they just use the same word for the api and the concept? If you're gonna refer to the concept as "action", then the hook should be useAction. And if you think "action" is a meaningless word and you need to add some explanation about mutation or promises in the docs, then maybe better just call the concept "mutation", "async transition", whatever and same with the hook.
I wrote an article which might help?https://alexkritchevsky.com/2022/10/12/react-2.html
It's based on a theory that hooks click better for a lot of people if they see an MVP implementation of one and understand the programming problem it is solving.
May I suggest a weird approach? Do this if you have the time but I had the same experience as yours regarding the mental model of React and that the ui is a function of your data.
I suggest you to visit Flutters docs and find the section about its architecture, it resembles React a lot!
There a components (Flutters calls it Widget) and each component has its own hooks and states (in Flutter you have setState), it actually helped me grasp the mental model weirdly enough.
AFAIK, the "use" convention is just a convention used to indicate that you're dealing with something that is plugged into React's state management system, and is going to deal with some kind of state change that can cause component re-renders.
It's helpful to remember that functional components are, well, just functions, which on their own don't have any way to preserve their own state without resorting to some kind of global state store. Unlike object instances, which can have members which keep their state across invocations to instance.render(), functional components are just functions which receive props and return something (usually a React.createElement invocation, often disguised with JSX). Since they don't inherently have any way to preserve state, React provides functions to manage state and to trigger re-renders of components. This is what hooks are - they're global functions which manage updating a global state dict behind the scenes, and triggering re-renders when state changes.
* useState declares a stateful variable which is preserved across renders, and a mutator function which is used to update that variable (in the global state dict) and cause React to perform a re-render of any components which depend on that variable.
* useEffect would probably be better named "useSideEffect", since its purpose is to run a callback as a side effect of one of its declared dependencies changing. It is a little overloaded, in that it can run its callback as an effect of: 1. The component initially mounting, 2. the component unmounting, or 3. one of the declared dependencies changing value.
* useMemo is kind of a combination of useState and useEffect, which declares a stateful variable that is preserved across component renders (the memoized value) and uses a generator function to regenerate and save a new version of that variable when a declared dependency changes.
* useCallback can be thought of as a specialized case of useMemo which returns a memoized function.
Essentially all hooks are built on these four (and really, just useState and useEffect, since useMemo and useCallback are trivial derivations from those two).
It's helpful to think about react state as eventual and to treat it as immutable, and to think of components as truly functional constructs, which should just receive external input and return an output. It may be helpful to think of useState values as nothing more than additional values passed to the function by React when it invokes them. When you update state (or run an effect) you aren't changing things in this invocation of the component, you're changing things for the next invocation for the component (and queueing a reinvocation).
Imagine that you have a declared hook `[someState, setSomeState] = useState();`
Calling `setSomeState(val)` doesn't change the value of `someState`, which you should treat as an immutable variable. Instead, it updates the value of `globalStateDict[currentComponentIdentifier]["someState"] = val` and tells React to queue a re-render of this component. React dutifully re-invokes the function, and the second time it's run, the local `someState` variable receives its value from the React-managed global state, which is now `val`.
useEffect is best thought of as a synchronization mechanism between external state and react state and the function it returns may actually be better thought of as a side effect. UseEffect makes sense in this case because you aren’t on the side!
Imagine if react was pure. Just a huge tree of components.
Each one is simply this: (your data) => <your html>
And then at the top you call render({ my data + functions }), your data propagates down the render tree, and you get an html page back. So simple! Just one function that you call. You put your data in the top, you get your html out.
Except.... what if that's too pure, sometimes. Can't a render function just remember a variable between calls? Why can't a render function two thirds down the tree fetch the data if it's needed? When things aren't so pure, you can optionally pull out hooks to break out of the purity. That way you don't have to do everything at the top level and outside of react, if you don't want to. Just bang a useState in at an appropriate level that makes sense, and it'll remember the state between renders.
TLDR - Hooks are a lie. Pretend “hooks” as a term or concept doesn’t exist. Treat every hook as a unique and independent concept and learn each separately and individually.
1. The purpose of specific hooks have silently changed over time - You’re not the only one confused. The React devs themselves were confused about what they wanted to do with hooks. For example, useEffect is for managing side effects according to the old documentation whereas the new documentation says it syncs external systems.
The change in behavior is ok, except the devs are not open about the fact that they’ve changed how they see useEffect. If they did that it would reduce some of the confusion, especially with the naming, since useEffect is named based on the previous purpose rather than the new.
2. Hooks are expensive - The React devs were far too hasty with the creation of hooks. For example, useMemo and useCallback are basically the same thing. There was no reason for both to exist but React devs considered hooks something easy to create and easy to understand so believe in creating many of them.
The problem, however, is that this approach is completely backwards. Creating a new hook should be considered extremely expensive and something to be avoided as much as possible. The reason is that while technically they are indeed often lightweight wrappers that are easy to create and deploy, conceptually they’re extremely heavy. Every hook brings highly impactful behavior which may not be entirely predictable without looking at the source code, and may not be related to other hooks in any ways.
3. Hooks are not a thing - Calling all of them hooks is also a massive mistake because there is very little similarity between their behaviors. The only similarities that exist are the restrictions on them. But there is no similarity in what they can do. So, for example, if you learn what useEffect does, you will have to expend the same amount of mental energy learning what useCallback does as someone who has no idea what useEffect does. As someone who knows about useEffect the only advantage you have learning about useCallback over someone who doesn’t is that you know you can only use it at the top level of a function and maybe a slightly better intuition of hooks breaking the pureness of functions.
4. It’s the Wild West out there - There are only 2 “Rules of hooks”. They must only be used in functional components. They must be used only at the top level of functional components.
The “use” hook doesn’t even follow these. The 2nd “Rule of Hooks” does not apply to it. The use hook does not need to be used only at the top level but can be used within conditionals and loops as well.
Conclusion - The reason you don’t understand hooks is because “Hooks” are a lie. They don’t exist. No one can go in and learn about “hooks” in React and do anything useful with that information. Instead, you have to learn about “useEffect”, and “useState”, and “useCallback” etc and treat them as completely independent and different concepts with no relation to each other to have learnt something useful.
Fundamentally hooks was a linguistic invention designed to hide the fact that when switching from class based components and the well established concept of a component lifecycle, the React devs created around a dozen new independent concepts to replace them. By pretending that all these different independent concepts such as useEffect, useState, etc were not actually independent concepts, but were a single concept called “Hooks”, they were able to sell the transition to developers more easily.
The only doubt in my mind is whether the React devs were even aware of this falsehood that they were spreading. I’m not convinced they themselves understood what they created and were laboring under the same illusions that they were spreading.
There is an underlying context here - hooks are "effects" from OCaml 5+ / Koka / recent Haskell / etc. Sebastian actually was asking in the ECMAScript mailing list several years ago about adding effects to JS. They built hooks hoping they'd get language-native support for extensible-effects.
Hidden amongst all those updates is the fact that React finally supports custom elements. Advocates of web components can finally just say "web components work in every framework" without adding any disclaimers about React [1].
Wow. useOptimistic is seriously cool. These are all really great tools to eliminate more and more boilerplate. Can't wait to put it all into use.
Gotta say, I really love what the react team has been doing, sure it hasn't always been perfect, but it really feels like inching closer to a very smooth developer experience very time.
Some inconsistencies here, metadata is added via jsx but preloading resources is done by some magic functions. Are they not hooks? what are they? Why there need to be this other way to make side effects?
It's been a couple of years since I was into React. What's the state of React? Where is it headead now? Are we over the SPA thing and returning to the age old RoR way?
From my POV, React is good and only getting better. Fundamentals aren't really changing, but the biggest pain points are being addressed. Hot reloading is faster thanks to the likes of Vite and SWC. Performance of package managers like yarn and npm have improved dramatically. Libraries like react-router-dom make life even easier.
I wouldn't expect React to be replaced any time soon.
I would say it's moving more towards a hybrid of SPA and non-SPA. The new features reduce the difference between front-end and back-end code and make it very simple to move some handling from the front-end to the back-end or vice versa if you choose.
The "old RoR" way assumed that all behavior is built by the server through ruby, until client side behavior was needed. Then, that was built in CoffeeScript. (or JS if you rejected omakase.)
The React way is to assume you will have client side behavior, but write it as if it is client-side and the server will compile that into a html that can be hydrated with behavior without intervention. Even with that "magic," it is easier to reason through if you already have a mental model of the browser.
To me it seems to be turning into php but with better developer experience. SSR is much better and fortunately React devs have also discovered that shipping 2MB+ of js at once isn't optimal.
Server rendered React components have always been in, and server rendering was the primary precursor to React in the first place. Still full circle, without coming or going anywhere.
RSC is not the introduction of rendering React components server side. React Server Components are concerned with new server-specific functionality for sure, but they’re also concerned with changes to bundling and wire format, mostly addressing client-specific concerns that arise from those.
But don’t take it from me, I’m just regurgitating information I learned from actual React team members (at least at the time) like Dan Abromov.
`react-dom` has a `renderToString` function since day 1 and people has been rendering server side since day 1 of React. There are also approaches such as pre-rendering with Chromium.
Granted I don’t know much about typing in php, but from my quick google search, it seems like they support type hints and type declarations, but the language isn’t strongly typed.
Also, to your second point, some of the largest, most critical, and most at-risk businesses on the planet (namely banks) run on COBOL, but I wouldn’t exactly describe cobol as a language that lends itself well to large orgs, it’s just entrenched. same as php and dozens of other technologies.
I admit I’ve only ever used Hack, not vanilla PHP, but that one is a pleasure to use. I’m sure the vast majority of my colleagues will agree with that too
It is brain dead. Vercel.js is making as much money as possible while there are still so much attention but most experts/evangelists left or are leaving for more modern frameworks like htmx, lit, solidjs, svelte...
If you actually follow the people in the React team, they've moved on to things that are not front-end framework. However lame React is these days, htmlx etc are even lamer. No one quits a well-paid job at Meta or Vercel to then go continue working on the same boring shit.
With the introduction of this "actions" stuff I have finally completed the last step to becoming the simpsons' meme "old man yells at <react>". As in, after using it since around 2016 I think I will be looking for something different.
Here is what I am struggling with: I am not able to grasp the programming model with Hooks. I am not able to read the code easily, nor am I able to easily understand the interactions in the app. "easily" being the keyword here. I can understand what is happening if I put in the effort, but every time, it is a struggle. I switch between languages and platforms all the time, but react code is where I have to take a real pause to understand what is going on.
My suspicion is that this has to do mostly with the names of the Hooks, and how they are used in the code.
* Why are they named useState, useEffect etc? Are there better names if used will make it easier for me to read this code? Are there any other systems/languages (even in JS) where similar constructs are present? What are their names?
* If JSX is anyway getting compiled to JS, why do I have to still deal with strange looking useState and useEffect declarations? Is there a way to get cleaner syntax and make React code read like regular code?
This is mostly a cry for help, and not a criticism of React. I have used React in the past (several years ago, before Hooks) and I used to "get" React.