Live data from Hacker News

In React {Transitions} = F(state)

jordaneldredge.com

41–50 of 55 posts

Re: In React {Transitions} = F(state)

#41

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?

Because (1) UI app development isn't simple, so there are many ways to cook the egg, and (2) React isn't opinionated, so there are a lot of competing options, and it has quite a large surface area of use-cases.

Re: In React {Transitions} = F(state)

#42
post #20

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 alle…

That works for a certain class of applications, but it's not very simple once you do want interactivity on the browser client.

Nor would I call it simple that the server has to be able to send the whole UI over the wire instead of just data. And it ties your server to the web browser instead of providing a simple data API that can be used by anything that can make an http request.

There are always trade-offs.

Re: In React {Transitions} = F(state)

#43

"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.

This is needlessly pedantic. useRef/useEffect are tools to implement the model on top of an imperative reality. Things like canvas rendering APIs don't have a pure interface, but it's still obviously very useful to provide one (hence libraries like react-konva and react-three-fiber).

Re: In React {Transitions} = F(state)

#44
post #34
post #8

Earlier quoted context omitted.

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.

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.

Try MobX. I think it's the holy grail of state management.

You have your app state in an object/class, and components automatically rerender when the part of the store changes that they access during render.

    class Store {
      counter = 0
      constructor() { makeAutoObservable(this) }
      increment() { this.counter++ }
    }

    const Component = observer(() {
     const store = useStore()
     const click = () => store.increment())
     return {store.counter}
    })
It has a very light set of idiosyncrasies for what it gives you unlike, say, redux.

Re: In React {Transitions} = F(state)

#45
post #19

Earlier quoted context omitted.

Hooks are the best thing for frontend dev since async/await.

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.

That’s true of every other GUI tech.

Angular too many digest cycles anyone?

Re: In React {Transitions} = F(state)

#46
post #9

The vast majority of state problems in React are a result of nonsense cargo culting around the idea that classes are somehow bad.

I disagree. With classes, everything was stateful (because, y'know, classes). People were doing all sorts of crazy thing with the lifecycle methods and it was always a pain to have to remember the "this scope" and bind your event handlers. I saw so many bugs written by people who lost track of what "this" was.

Both paradigms have foot guns but having used both I much prefer the hook version.

Re: In React {Transitions} = F(state)

#47
post #5

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.

I've seen some pretty good React codebases and I've seen plenty of backend spaghetti code. In all cases it's not the tools, it's the programmers and usually it's layers and layers of people not taking the time to write clean code. Probably because their management doesn't value it or they don't have someone with the experience necessary to guide them towards clean code.

Re: In React {Transitions} = F(state)

#48

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.

It doesn't have to be this way for most apps. One reason I've seen why people heavily rely on the lifecycle methods is that UI = f(state) isn't fast enough. But in more powerful languages like ClojureScript, you can keep track of which part of the state is accessed, and subsequently rerun only parts of the f that needs to rerun. As I understand, there is something called React compiler (https://github.com/facebook/react/tree/main/compiler) that tries to do this. But in a better language, this doesn't need to be a standalone tool, just a macro.

Re: In React {Transitions} = F(state)

#49
post #34

Earlier quoted context omitted.

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.

Try MobX. I think it's the holy grail of state management. You have your app state in an object/class, and components automatically rerender when the part of the store changes that they access during render. class Store { counter = 0 constructor() { makeAutoObservable(this) } increment() { this.counter++ } } const Component = observer(() { const store = useStore() const click = () => store.increment()) return {store.…

That looks pretty good! I actually implemented my own state management that works like that five years ago because I didn't like the options at the time.

https://github.com/Facepunch/react-class-model (note: context is not required)

Re: In React {Transitions} = F(state)

#50

Earlier quoted context omitted.

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…

> 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…

Believe me, I've read that essay from start to finish, but as I mentioned, it was in the heat of the moment and I didn't have much time to architect something more proper.

> 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.

Well, the problem in this case was that the affected useState was not just a pure function of the useState that caused it to be modified: other actions could modify it as well. (E.g., you have some form state that should get updated whenever a state value somewhere else is changed.)

I believe useReducer is a bit closer to the use case I'm thinking of, but the dispatch functions for that are verbose and unpleasant to write. Presumably ad-hoc closures wrapping the setter functions would be somewhat more lightweight.

Post reply on HN