News for hackers. Stuff that matters.
Re:The Plan for React 18 by tekstar on Tuesday June 08, 2021 @02:50PM (#27439259)
I use React (well, Preact) every day.

I use it 2014-style. Class-based components, componentWillMount, render, callbacks, and that's about it.

I love this workflow, and generally structure all my UIs this way regardless of platform - have a state struct and then fully render the UI as a function of the state. To me, that's the big hurrah for using React.

But I have no clue why React is at version 18 and why it keeps getting new features. I'm perfectly happy making quite complicated UIs with the pattern I know well. Should I be following along? Does it matter?

Re:The Plan for React 18 by enlyth on Tuesday June 08, 2021 @02:55PM (#27439322)
I personally fell in love with hooks after initially disliking them, you should give it a try, maybe in a toy personal project, to see if you like it. It is great for separation of concerns.

You basically stick to writing pure functional components focused only on how to render, and try to abstract reusable logic into hooks, and expose only what you need

For example, you could make a useApi() hook and inside your component just do const { data, loading, error } = useApi('/endpoint'), so you can hide everything you don't need away from the rendering logic

Re:The Plan for React 18 by enumjorge on Tuesday June 08, 2021 @03:42PM (#27439828)
> You basically stick to writing pure functional components focused only on how to render

If you’re using hooks like useState or useEffect I wouldn’t consider those functional components pure.

Hooks provide some nice syntactic sugar, which is not nothing, and make it easier to share logic between components. In my experience hooks have made my code easier to read, but they haven’t simplified it. The side effects and state might not be inlined but they’re still there. If anything they’ve made it less explicit because some of the details are hidden behind the magic that the React runtime uses to add state to functions.

Re:The Plan for React 18 by nexuist on Tuesday June 08, 2021 @05:41PM (#27441266)
They're technically not pure, but they're as close as we can get to functional-style state handling: declare dependencies upfront so the caller knows exactly what they'll get when they execute your function. Fully state-less code achieves basically nothing; you need to "escape the hatch" eventually to work with the rest of the architecture. Hooks are very beautiful escape hatches that let you deal with persistence without having to sacrifice the rest of your function's body to it.
Re:The Plan for React 18 by bern4444 on Tuesday June 08, 2021 @06:58PM (#27442174)
Really well said.

And if you really wanted to make it 'pure', you could easily write a hook with an explicit return type that wraps the type of the initial value. If you're using typescript, you can then limit the possible types of the generic to only monads.

    type State<T> = val as T;

    const useStatex = <T>(initialState: T) => {
        const [state, setState] = useState(initialState);
        return [state, updateState] as [State<T>, (val: T) => void];
    }
This new hook, useStatex, has an explicit type definition that indicates something stateful is taking place. Same as Futures. You can take this even further in the typing limiting the generic to only allow certain types for the underlying values to be monads, or even more simply

    type State<T> = Promise<T> | Array<T> | Option<T>
So you avoid an extra layer of nesting like

    State<Future<Array<T>>>
Point is, there are lots of ways to easily resolve any its not pure! arguments same as any other functional programming concept

eta

The simplest way to limit the return type might even be to just do this

    const useStatex = <T extends Promise | Array | Option>(initialState: T) => {
Re:The Plan for React 18 by bern4444 on Tuesday June 08, 2021 @03:58PM (#27439992)
I’m sure the parent author knows this

But the beauty of hooks is as you say reusable statefull behavior. It also lets you treat your functional components more like a pure function in my opinion.

If the hooks you use are poorly designed, then yeah, it may be more difficult. But well designed and implemented hooks make your component appear more like a pure function.

The state is (more) decoupled from the UI code than before and lets me easily reuse behaviors across components.

Re:The Plan for React 18 by flowerlad on Tuesday June 08, 2021 @03:32PM (#27439720)
> pure functional components focused only on how to render, and try to abstract reusable logic into hooks

Just FYI, once you add hooks, it is neither pure nor functional.

https://mckoder.medium.com/why-react-is-not-functional-b1ed1...

Re:The Plan for React 18 by WorldMaker on Tuesday June 08, 2021 @04:35PM (#27440415)
They may not be pure, but they are still functional. The hooks follow similar laws to Monads. They aren't entirely monadic and it would have been nice if they were and used a more monadic combinator for bind [1], but they are a relatively pragmatic solution for a language without a strong type system to encode things like algebraic effects and monadic bindings in.

[1] Mostly useless aside: using a .then()able based plumbing would have opened up the possibility of using the async/await combinator language. The names async/await would give the wrong impression especially prior to the actual concurrency changes to eventually ship in React 18, but would have potentially been a more monadic fit.

Re:The Plan for React 18 by flowerlad on Tuesday June 08, 2021 @04:42PM (#27440499)
> The hooks follow similar laws to Monads.

And monads are impure [1]. If all your functions are impure then you're not doing functional programming.

[1] https://alvinalexander.com/scala/io-monad-doesnt-make-functi...

Re:The Plan for React 18 by 1_player on Tuesday June 08, 2021 @06:00PM (#27441519)
> monads are impure

Not necessarily. The IO Monad (Haskell et al.) is impure, a monad is just a functional abstraction that doesn't have anything to do with purity at all.

Re:The Plan for React 18 by WorldMaker on Tuesday June 08, 2021 @05:20PM (#27441014)
Yes, I stated that. Those functions are impure. Purity is a lovely goal, but purity also isn't a defining characteristic of functional programming, it's a modern pursuit. I've met enough classic LISP practitioners that lived their whole programming lives in the most impure of functional programming, that I would never want to tell them to their face that what they did didn't count as functional programming because of all the leaky impurity in LISP (due to pragmatic considerations of the time).
Re:The Plan for React 18 by flowerlad on Tuesday June 08, 2021 @05:26PM (#27441083)
> purity also isn't a defining characteristic of functional programming

Disagree. It is in fact the defining characteristic of functional programming.

Re:The Plan for React 18 by e12e on Tuesday June 08, 2021 @06:30PM (#27441926)
It may be defining of pure functional programming. But not for "functional programming". Some arguments for why (and indeed some discussion for why not, too !) : https://wiki.c2.com/?FunctionalProgramming

Ed: and I suppose if a function call allocates a stack frame it's no longer a pure function? Or are all functions of type crash-or-value?

Re:The Plan for React 18 by bern4444 on Tuesday June 08, 2021 @10:08PM (#27443445)
If you get really technical, any program is impure as running the code has the side effect of increasing the temperature outside the cpu from running the program. That's a side effect. And running a program is going to change the temperature in a different way each time

That's to say, at a certain point, all this is arbitrary.

Pure code is generally easier, but a program that's only pure code is pretty useless. You always need an escape hatch which is what some monads like IO or Futures provide. Monads and other functional paradigms allow us to write and interact with impure code in a pure way and mindset. That's exactly what hooks do as does the react mindset of, your view is a function of state.

Hooks easily let us separate that statefulness into their own abstraction - just as futures do for async calls, and IOs do for the file system. This lets us model our view as a function of state (and props which are just arguments to a function)

Re:The Plan for React 18 by flowerlad on Tuesday June 08, 2021 @10:56PM (#27443716)
> Monads and other functional paradigms allow us to write and interact with impure code in a pure way and mindset.

No. You can't interact with impure code "in a pure way". That makes no sense whatsoever.

I don't think you read the article I linked to earlier. Here it is again: https://mckoder.medium.com/why-react-is-not-functional-b1ed1...

Re:The Plan for React 18 by bern4444 on Wednesday June 09, 2021 @10:21AM (#27448180)
It lets us think like that despite it not being true.

You need state to do anything useful. A lot of functional programming revolves around the idea of isolating impure aspects of a language from the pure parts.

That's why we have Futures, IOs, Options, Eithers etc.

No one is saying they are pure, the types are an indicator that something impure is happening. They are abstractions that allow us to pretend they're pure and work with them regardless of the context of the type.

I can map over a Future, IO, or Option regardless of whether the Future resolved, the IO was successful, or the Option contains a value.

That's a functional mindset where the impurity is isolated to the data type and methods are exposed on the type that lets us ignore certain possibilities.

I don't care about the context when I map over one of these types, whether its a Future, Option, Array, IO etc. I can write my pure function and pass it off to map. Who cares if the Future really contains an error, the Option is None, or the Array is empty. Map handles all those cases for me and lets me interact with these impure aspects in a pure way.

The function I define and pass to map is pure and lets me interact with impure parts of the code in a pure way.

useState and useEffect should be thought of in the same way. Clearly it denotes something impure is happening, but the stateful value can be treated like a state machine that can be declaratively tested against a finite list of possible states.

In the case of a Promise, it's successful, pending, or error. For an Option its Some<T> or None. Etc etc.

If my hook returns 3 values, result, isPending, error (and if you really want, each value can be an option), I can easily handle each scenario deterministically.

That allows for pattern match like solutions (in JS it can be through cases clauses since there's no FP pattern matching).

This allows for writing components in a pure like approach even when its obviously impure.

Re:The Plan for React 18 by flowerlad on Wednesday June 09, 2021 @12:34PM (#27449934)
In real-world FP programs there will be some impure code. But that impure code should be in thin outer layers. The core needs to be pure. Why? Because otherwise it defeats the purpose of FP. The purpose of FP is easy verification and ease of reasoning about code. That's only possible if most of the code is pure functions.

There is really no need shoehorn something that's not a good fit for FP into the FP paradigm. It is not like customers are going to pay more money if it is FP. So don't bother.

Re:The Plan for React 18 by jfengel on Tuesday June 08, 2021 @03:00PM (#27439373)
I find the function-based components much more elegant than class-based components. The semantics of Javascript classes are confusing, and the new notation is very concise. (Especially with an IDE, such that "refactor this pile of tags into a function" is a one-click process.)

The useState hooks are a tiny bit clearer than the setState semantics. The effect hooks are less clear, but all told, the new mechanisms for handle global state and side effects better without Redux. (Redux is neat, but after working with it for years, I just have to conclude that in most cases it's just too much mental overhead compared to a more idiomatically Javascript solution.)

There's nothing wrong with continuing to use class-based components, but I think you'll find that everybody else is going to gradually deprecate it. The key facts about the work flow -- state to render function to surprisingly efficient DOM reconciliation -- remains the same.

Re:The Plan for React 18 by dstaley on Tuesday June 08, 2021 @02:55PM (#27439317)
As someone who was initially resistant to hooks, I actually find that they're a more expressive API to how I was already thinking about my applications. There's footguns for sure, just like there are with class components, but I found that rewriting my class components with hooks instead actually made the code cleaner and easier to reason about. That being said, it's possible the benefit simply came from the rewrite, but even with newer components, I feel like hooks are a better API.
Re:The Plan for React 18 by srpoder on Tuesday June 08, 2021 @02:55PM (#27439321)
React hooks might be the best feature ever, once you understand it, it provides you a way to write highly reusable code.
Re:The Plan for React 18 by flowerlad on Tuesday June 08, 2021 @03:03PM (#27439408)
I am with you. React as originally designed made sense to me. You render the screen point-in-time and React takes care of updating the screen efficiently. This is all I need from React. Everything else is bloat.
Re:The Plan for React 18 by e12e on Tuesday June 08, 2021 @06:51PM (#27442131)
Wasn't react first designed in standard ml, without classes? Then classes were bolted on in the js rewrite - and hooks are closer to the original design?

https://www.reactiflux.com/transcripts/jordan-walke

> So I continued to explore framework-izing these ideas, and I had implemented several iterations of what eventually became React, in a few languages - one of the first explorations began as a rough implementation of the reconciler and component model in Standard ML (CreateClass was a "module function"). This was really great because SML embraces immutability by default which is natural when building React style components. We naturally wanted to deploy UI to web browsers, and at the time, the compile-to-JS landscape was not as mature as it is now - I don't even think source maps existed yet. So it made sense to port that exploration to JavaScript (...)

> One thing I noticed that when people were creating point to point bindings in their more traditional "MVC" app structure, it would almost always end up requiring "computable" bindings which invoke a function anytime a mutable cell had received a "change event". All these "computable bindings" ended up chaining together and small changes would end up causing large recomputation of the majority of the UI. I realized that functions already do transform inputs into outputs, and if we could just find a way to reinvoke those functions repeatedly, and quickly enough, that we could be much more expressive and concise, at not much more performance cost that the chain reaction that "computed bindings" would result in anyways.

Re:The Plan for React 18 by no_wizard on Tuesday June 08, 2021 @02:55PM (#27439315)
In this way react is choose your own adventure. There is no current signal that the way class components work will change and I don’t exactly expect that to happen any time soon if at all. Rather then new features are aimed at developers with more complex use cases and make heavy use of asynchronous data fetching in a way that lends itself to concurrency.

If this isn’t you I’m sure at least the general performance improvements will be nice otherwise I don’t see why you can’t just keep doing what you’re doing

Re:The Plan for React 18 by thatswrong0 on Tuesday June 08, 2021 @02:57PM (#27439339)
So you're saying you have no idea why they're making changes because you haven't been following along, despite using the library every day...?

The communication about the "why" of new features has been extremely clear. E.g. for hooks: https://reactjs.org/docs/hooks-intro.html

Re:The Plan for React 18 by tekstar on Tuesday June 08, 2021 @03:03PM (#27439402)
Your first sentence is correct. I'm quite happy using it the way I use it and don't hit any really sharp edges.

Thanks for the link, I remember when Hooks came out but I didn't feel the need to adopt them, I'll take a look again.

Re:The Plan for React 18 by joshxyz on Tuesday June 08, 2021 @05:18PM (#27440958)
I think it's less about being pure or functional, but more about being "ergonomic". I abhored class-based components from day 1, but on hooks everything just clicked.
Re:The Plan for React 18 by audit on Tuesday June 08, 2021 @10:11PM (#27443467)
>".. I use it 2014-style ..." are you using any type system eg TypeScript or Flow ?

I am asking because I do not remember them being used back then, so wondering if you had upgraded there.

Also what do you use for 'whole app' state handling (rather than component level) ?

Asking because React Context feature seems to be the right fit for the 'whole app' state handling, but it was not there back in 2014.

I also like you picked up preact for smaller project.. just because the size is so small. But for lager things (eg over 20K lines of JS) I seem to be staying with React.