[HN Gopher] In React {Transitions} = F(state)
___________________________________________________________________
In React {Transitions} = F(state)
Author : captbaritone
Score : 35 points
Date : 2025-04-07 20:28 UTC (2 hours ago)
(HTM) web link (jordaneldredge.com)
(TXT) w3m dump (jordaneldredge.com)
| dvtkrlbs wrote:
| I dont think this is really true in practice. Most of the time
| there is context and 3rd party sources components get from. It is
| good idea to have your actual view use this paradigm though.
| dfabulich wrote:
| > A React application can be thought of as modeling a state
| machine. Each render takes a state and produces the UI for that
| state. This is the famous UI = f(state) mental model of React.
| But, for complex applications, formally enumerating a transition
| table is often not feasible. When the number of possible states
| is not finite, a table will not suffice and we must instead
| define a mapping: a conceptual function which takes in a state
| and returns the set of valid transitions for that state.
|
| Not really, though. While you _can_ model any program as a state
| machine, doing so typically adds nothing to your understanding of
| the program.
|
| State-machine diagrams are especially useless. A diagram is only
| useful if it has about a dozen things in it, maybe two dozen,
| maximum. But that doesn't mean you can model a dozen _states_ in
| a state-machine diagram; in these diagrams, the _transitions_ ,
| the arrows between the states, are at least as important as the
| states themselves. So the diagrams are useless when the number of
| states + the number of transitions between them are greater than
| a few dozen. Typically that means state diagrams are only with a
| handful of states with a few transitions hanging off of each.
|
| But, if your problem is simple enough that you can represent it
| with a handful of states with two or three transitions each, then
| you have a _very_ trivial problem, so trivial that the state-
| machine diagram likely added nothing at all to your understanding
| of it.
|
| This is why no popular UI frameworks actually _do_ model UI as a
| set of states with transitions. It 's easier to model the _state
| diagram_ as a _function_ and then just forget about the state
| diagram.
|
| That's what React is all about! A pure function, UI = f(state).
| It's _better_ than a state diagram.
|
| This article is saying: "Hey, you could think of React, something
| conceptually simple, as something unnecessarily complicated,
| instead!" Gee, thanks?
| captbaritone wrote:
| Author here. I think we might actually be in agreement. My
| point is that in React you don't formally describe the
| transition table because (and I think this is where we agree)
| that's infeasible for an app of any reasonable size.
|
| The observation I'm trying to capture in this post is that even
| though we don't define a formal transition table, we actually
| _do_ implicitly define the set of valid (user) transitions for
| each state via the event handlers we bind into the DOM when our
| React component tree renders that state.
| tshaddox wrote:
| > But, if your problem is simple enough that you can represent
| it with a handful of states with two or three transitions each,
| then you have a very trivial problem, so trivial that the
| state-machine diagram likely added nothing at all to your
| understanding of it.
|
| And yet, it's extremely common to see apps with clearly broken
| states and state transitions for what should be relatively
| "trivial" state machines. Think play/pause buttons, buttons
| with loading states, form fields with error states, etc.
| revskill wrote:
| That is a valid way of thinking.
| mvdtnz wrote:
| Every time I delve into a large React codebases (and I have
| worked on some real monsters) I have a laugh to myself at how
| badly these guys tie themselves up in knots in order to preserve
| the supposed simplicity of the state -> UI function. When you
| invent something as insane as the hooks API in order to maintain
| purity it's time to step back and consider if you're really on
| the right track.
| paulddraper wrote:
| Hooks are the best thing for frontend dev since async/await.
| recursive wrote:
| I would believe that if there were exactly two things in
| front end.
| LunaSea wrote:
| I can't count how many issues I've seen due to: missing
| useEffect dependencies, cyclical hooks, unnecessary
| rerenders, etc. linked to this API.
|
| It has a lot of expressivity but is incredibly brittle and
| dangerous.
| taeric wrote:
| I want to disagree with you, but I just can't. Every simple
| example on the different ideas for managing state in React is
| easy and seems reasonable. Every application I encounter seems
| to quickly take that and just start laughing at me.
| CharlieDigital wrote:
| Something with React's approach is fundamentally broken, IMO,
| and this is why we see so many variations of state management
| libraries on React that we don't see on other frameworks
| because state kind of "just works" and is really, really
| simple when you are using signals.
|
| My sense is that in React, the complexity comes from the
| management of minimizing the "blast radius" of state changes
| to prevent over-renders. So there are a lot of different
| approaches and ways that folks have cleverly engineered to
| solve this problem, but none of them feel as simple as say
| Pinia on Vue, for example.
| Rohansi wrote:
| I think state management is the worst part of using React.
| All of the popular/highly recommended packages to manage
| state require you to write code in unconventional ways
| without really explaining the design decisions. Why use
| reducers? They're basically different (worse) syntax for
| mutable object method calls.
| eddythompson80 wrote:
| To me, the state -> UI paradigm isn't simple in the sense "oh,
| that was one click, simple". It's simple in the sense "anyone
| can do it if you just understand/follow these 10-15 _simple_
| rules ". Once you know these simple rules, you can jump
| straight into 95% of react projects and be productive fairly
| quickly.
| jschrf wrote:
| The vast majority of state problems in React are a result of
| nonsense cargo culting around the idea that classes are somehow
| bad.
| recursive wrote:
| IMO it's the central tenet to the dogma that "state must not be
| mutable".
| geetee wrote:
| The absolute nightmares people create in order to attain this
| ideal...
| kccqzy wrote:
| I'm glad I learned React during the time when React.createClass
| was the only way. It was simple and intuitive. At that time the
| docs included a very lengthy discussion of what should be put
| inside the class and what should be passed via props. It was
| very helpful when it comes to teaching newcomers to architect
| their app. It also carried over the years of intuition by the
| typical dev working with OOP. Much better than the current
| trend of using hooks for everything.
| tripplyons wrote:
| I might just not be aware of a better alternative for React
| hooks, but I don't like useEffect. I feel like it makes it much
| more difficult to manage state and transitions compared to
| SolidJS or other frameworks that use signals.
| alpinisme wrote:
| There's no denying that the idiomatic solution is sometimes far
| from obvious, but idiomatic react wants useEffect to only about
| synchronizing react with external systems. Everyone reaches for
| it to synchronize between components and do all sorts of other
| non-idiomatic things though, and that's where the pain comes
| in.
| LegionMammal978 wrote:
| Out of curiosity, I just looked through some of my old code
| calling useEffect. Most of it was for fetching data from an
| API on mount; I'd also written a custom little hook that
| returns a callback to signal that the data should be
| refreshed.
|
| But a few instances were to conditionally set one piece of
| state whenever another piece of state was changed, arguably
| an abuse of the mechanism. I suppose the proper way would be
| to wrap the setter function into one that changes both, but
| it takes a fair bit of discipline to avoid useEffect in the
| heat of the moment.
| wk_end wrote:
| There's an excellent article in the React documentation
| about this ("You Might Not Need An Effect"). Back when I
| was working on a React team I probably threw it at a code
| review on average once a week.
|
| I really like React, but given the way developers seem to
| struggle to use it "correctly" (despite all the lint hooks
| and weird diagnostics like double rendering to help) it's
| hard not to feel like there's something wrong with it.
| marksomnian wrote:
| > But a few instances were to conditionally set one piece
| of state whenever another piece of state was changed
|
| That use case is explicitly called out on the "You Might
| Not Need An Effect" article in the docs (which everyone
| writing React should read, and arguably was published years
| too late): https://react.dev/learn/you-might-not-need-an-
| effect
|
| TLDR:
|
| When updating a useState based on another useState, don't
| use the first useState at all, just compute it inline. If
| it's expensive, wrap it in a useMemo.
|
| When updating a useState based on props, call the setter
| _directly from the component function_ , and React will
| immediately re-render the component (instead of rendering
| it, running the effect, and then rendering it again).
| Jcampuzano2 wrote:
| A lot of the time it comes down to the platform not actually
| providing easy ways to do things that users are reaching for
| effect for.
|
| For example some people reach for it for fetching data in
| routes. It wasn't until recently that routers started to come
| with built in patterns to do this without effects - example
| being react routers (it's been a while since I used but remix
| had this) loaders and tanstack routers beforeload and
| loaders.
|
| People fetched in an effect because at the time this was the
| most simple and obvious place to do it unless you were very
| aware of the other ways to do it, and we didn't have
| primitives like react query either.
|
| Another example of a non obvious things logging an analytics
| event when a specific component renders. You could attempt to
| tie this to the specific update that caused a component to
| show but that update may be very complex or hidden since your
| component could show based on a variety of states and require
| so much more work vs just logging in an effect.
|
| I guess one could argue both of these themselves are syncing
| operations, syncing your network state and server state for
| API requests in routes and analytics. But at the same time
| reacts team told everyone if you're fetching in effects
| you're doing it wrong without providing the answers.
|
| That to say yes effects are not a very good pattern for many
| things we use it for and should be avoided, but react as a
| framework (yes it's basically framework in my opinion, we're
| well past just. library point) itself does not educate well
| or have easy to understand built in ways to do these things
| that are VERY common use cases
|
| And this as someone who writes mostly react.
| kccqzy wrote:
| The most direct way of solving the immediate problem is to make
| transitions idempotent. Why must it be an error to complete an
| already complete TODO? Completing an already complete TODO should
| be a no-op. That simplifies things greatly.
|
| Of course many actions logically cannot be made idempotent, but
| for the subset that can, do it as much as possible.
| a_wild_dandan wrote:
| Exposing _invalid_ transitions to a user is a bug. Idempotency
| here doesn 't solve anything, just hides said bug, which is
| arguably _worse_.
| veidelis wrote:
| "This is the famous UI = f(state) mental model of React".
| Famously incorrect generalization. Why? For example, the useRef
| hook enables components to hold their own state. React components
| are not guaranteed to be pure functions. Of course, it can depend
| on how one writes their code, but it's not a guaranteed that UI =
| f(state) in React in general.
| guhidalg wrote:
| It's a mental model, not how it works. Your computer isn't
| actually executing C code, but it's helpful to think that it
| does.
|
| If you write React code that strays from that model, you better
| know what you're doing. When I have to reach for `useRef`, I
| know that I'm in dangerous water.
| ketzo wrote:
| "All mental models are incorrect; some mental models are
| useful"
| bob1029 wrote:
| The #1 reason I push for SSR/vanilla web is to consolidate all
| state to the server. Literally the only thing on the client could
| be a session cookie. A few hundred bits of entropy. That's the
| client's state. Imagine how simple that would be.
|
| The cost of a round trip for every UI interaction might seem
| high, but I've never seen a distributed client/server state
| machine model that could compensate for any of these alleged UX
| harms without simultaneously bringing in more complexity than
| anyone was prepared to deal with.
| adamddev1 wrote:
| But then we lose the ability to do anything offline. Offline
| web apps are still valuable. Some people want to turn their
| data off sometimes. Many people live in places where internet
| access is spotty.
|
| I also love the simplicity of SSR/vanilla web for some things.
| But I say keep offline-first SPA/PWAs alive. Cross-plaftorm.
| Freedom from the app stores. Freedom from needing to be tied
| online all the time.
| LegionMammal978 wrote:
| Yeah, sites demanding a roundtrip for every small interaction
| can be a pain to use when traveling. The principle I'd wish
| more web devs would keep in mind is, "Just because the client
| managed to contact your server once doesn't mean it will have
| fast and easy access to it in perpetuity." Indeed, in my
| experience, too many roundtrips is the cause of most
| atrociously slow websites, regardless of how heavy or light a
| framework they use.
| adamddev1 wrote:
| When you have a website that needs to be always accessed
| online, absolutely, give us an old-fashioned SSR vanilla web
| experience. Just give us a page WITH ALL THE DATA that loads
| in half a second. Don't make us wait for 5 seconds with
| spinners and placeholders while you make the client fetch
| data itself from different sources. This is insanity and
| torture! People are using client side rendering for the wrong
| things.
|
| But there are good and powerful use cases for client side
| rendering.
| nkrisc wrote:
| Freedom from browsers - I'd rather have an executable I can
| run.
| bob1029 wrote:
| > I say keep offline-first SPA/PWAs alive.
|
| I have no problem with the properly offline-capable apps
| using standards compliant web technology. I've been
| championing the use of PWAs to circumvent the iOS App Store
| for years.
|
| To be very specific, the problematic solutions in my view
| tend to be those right in the middle of pure SSR and pure
| client. They aren't sure if they are always online or offline
| by default and the actual customer use cases don't seem to
| have been fully explored.
|
| Did you ask the customer if a ~150ms form post to us-east-1
| from their main office would be something they'd even care
| about? Why not? You could save an unbelievable amount of
| frustration if they don't care. It would take 10 minutes to
| set up a demo they could try if you think it's going to be a
| deal breaker at delivery time.
|
| I've not once worked with a B2B customer in the banking,
| insurance, finance, manufacturing or retail domains who
| raised a concern about any of this. Only nerds on the
| internet seem to fantasize about the customer getting
| outraged at a browser navigation event or a synthetic browser
| benchmark score.
| whalesalad wrote:
| Why does it feel like React (not just the lib but the
| community/ecosystem/everything) took something as straightforward
| and easy to understand as functional programming and surrounded
| it with so much fluffy pomp and circumstance that it is
| unrecognizable?
| the_gipsy wrote:
| I've never seen a Teact project where UI = f(state). There is
| always heavy reliance on the "lifecycle" of components. So you
| compose "functions", but every function is using some global
| state, shared or not, it's meaningless to describe it as
| "functions".
|
| The one project I've used that had redux was also a complete
| nightmare to work with, and hooks are the blessed way now
| apparently.
___________________________________________________________________
(page generated 2025-04-07 23:00 UTC)