Hooks elucidate everything I've felt wrong about React, but have not been able to put my finger on it until recently.
Hooks reveal two major things with React:
1) React developers did not understand the component paradigm that they originally went with. If they did, then they would understand how silly it is that components cannot reuse logic. This was an entire debate many years ago. Composition vs. inheritance. You don't need to throw out classes or objects to get reuse.
2) React developers do not understand functional programming. I could write an entire essay on this. But it should suffice to say, FUNCTIONS DO NOT HAVE STATE. What React hooks introduce has more in common with dynamic scoping, of older LISPs. It fundamentally breaks lexical scoping, which is incredibly important for understanding code flow. You have to be constantly aware of when it's safe to use certain variables and the implications of using variables in certain scopes now. In 2020!! This is INSANE.
This sort of post that asserts that nobody understood or put delicate thought into something is just pompous and lacks intellectual curiosity.
At least respond to their rationale. In doing so, you’ll find that everything is just trade-offs.
btw Dan Abramov is great to follow on twitter. He often responds to criticism and clarifies React decisions and links to good blog posts. If you use twitter it’s a nice way to get polite, bite-sized wisdom about React and Javascript. At the least you’ll realize how much good thought goes into React.
> React developers do not understand functional programming
As some sibling comments note, this is not a fair conclusion to draw. And not that it disproves your statement, but Reacts original creator Jordan Walke wrote the first React prototype in SML. Not understanding functional programming is not on the list of things I would ascribe to him. He's a smart guy.
On a slightly different note, I'd recommend anyone try out Reason. It's slowly maturing and can be a real joy, at least compared to JS/TS.
Yeah, I'm not really plugged into the community that well but I think reasonml.org is the long term plan and that some sort of transition might be going on? I've mostly used reasonml.github.io and Bucklescript docs, but lately I've started using the Discord channel and it's very welcoming, friendly and helpful!
RE: 1) "it is that components cannot reuse logic" - +1 to this - recently I re-watched original hooks talk by Dan Abramov and was not able to finish it with conclusion different than "you guys really fix issues you invented before". Class-based components and reusability of logic is something that existed years before React, and probably will exist years after React. Even this concept of Dependency Injection and Services that Angular is still on proves that there-are-solutions. There are solutions for reusing logic between classes. Thing that bothers me the most is not that there's something wrong with fixing your own issues, but the fact that developers outside React Core Team start to think that "well, you cannot reuse logic between components".
Angular does not have a solution for this as far as I know. It's not about re-using logic. It's about re-using reactive logic that ties in to your component's lifecycle.
Who says functions don't have state? Referential transparency requires no such constraint; it only requires that state not leak into or out of a pure function save through its arguments (inward) and return value (outward). Beyond that, what they do within the space of their own lexical scope and the lifetime of their call stack frame is entirely their own business.
I'm familiar with dynamic scoping via Emacs Lisp. I have yet to encounter anything like it in React, and it'd be surprising in any case to encounter dynamic scope in Javascript, a language which does not even support it. The closest I can come to understanding what you must mean here is to think you're very confused about how React props work, but that doesn't seem likely either - I can hardly imagine someone having such an evidently strongly held opinion about something, and having that opinion turn out to be based on a fundamental misunderstanding of the subject.
Would you mind explaining in some more detail the issues you see with React functional components? You mention having an essay's worth of material, and while that's probably more than we need to support a discussion, perhaps you'd be so good as to boil it down to a few points with a little more substance to them than "React developers don't know what they're doing" and "this is insane".
> it'd be surprising in any case to encounter dynamic scope in Javascript, a language which does not even support it.
Doesn't matter much, but just b.c. it's interesting: JavaScript actually does support limited dynamic scoping - `this` is scoped dynamically like in usual Lisps, and there's a with statement[0] that acts somewhat similar with `let` in Lisp.
The "idea" that react hooks try to implement is very common in FP languages though. It has a lot of parallels with extensible effects; which is a pure, functional embedding of the idea of hooks
I think this is mostly a disagreement around terminology.
The GP is referring to purely functional languages like Haskell, where functions don’t have state and are referentially transparent. In Haskell, useState would have to use a monad.
Racket (and Lisp in general) has mutable state so doesn’t guarantee referential transparency. You can definitely write pure functions, and that’s good style in many contexts, but it’s not required or enforced.
I personally agree with the GP, and assume “functional programming” to mean pure functional programming. It’s common to use an FP style in non-pure languages, but I think this is FP if and only if you completely avoid state.
One way or another it's fine to consider methods that explicitly use state as 'not functions'. This is the mathematical definition after all.
That definition leads to the conclusion that hooks aren't functions, which seems fine honestly. I mean, why insist on using them as functions when they're clearly not? Their syntax is a bit unfortunate, as is the fact that you're not forced to declare them immediately at the start of your function, which looks like it would have cleared up many of the potential problems. Either way their use case is clear, using hooks seems to basically dynamically declare a state monad for that particular function (hence why I'd recommend doing this upfront).
I'm not a React programmer though, so take this with a grain of salt.
> how silly it is that components cannot reuse logic
It may be that your component is too complicated. Components should only have UI code. First move business logic out of the component, into your model layer, and make it reusable there. This step will eliminate most of the need to reuse logic in components. If you still have logic inside your component that you want to reuse consider restructuring your component into multiple simpler components.
When saying that "functions do not have state" without mentioning monads and encoding effects in type systems, it doesn't sound like you have enough experience with functional programming to assert your second claim.
Huh? You can treat state as arguments to your function. For a given function evaluation, the state is stable. The fact that state can be changed during event handling is 100% irrelevant to the evaluation. There is no dynamic scoping.
I feel you don't understand how React function components work. From a purely functional standpoint everything a function should have access to must be passed in as an argument. Any state that exists is always external to the function. Therefore hooks like useState can't exist because it creates state within a function. This is not only weird from a purely functional perspective it's also incredibly weird from a regular OOP perspective because that state should have been declared inside a class or struct. Therefore it is neither pure FP nor pure OOP. It's a random mix of both but it fools beginners into thinking that because it is not OOP it surely must be functional programming.
The reality is that a component in React is still a class with internal state. React hooks are merely using a reference to "this" behind the scenes to store state but hooks are the only way to access that state. Therefore React hooks are basically a small DSL that adds features like dynamic scoping which is why lots of people think that this isn't regular Javascript anymore.
Can you please give an example of React hooks 'dynamic scoping'? See https://stackoverflow.com/a/22395580 for an introduction to dynamic scoping.
React hooks 'state' variables are scoped to a single function. They are not arbitrary variables, but represent inputs to the program. The mental model is a function that produces the same output given the same inputs. Think of a dropdown, where the associated state variable D my have values a, b or c, depending on what the user chooses. The render function simply does not care how the value of D was set, and renders the exact same jsx given a specific D value: jsxa for a, jsxb for b and jsxc for c. That is as pure as it gets. Furthermore, the dropdown state variable D never represents the intermediate computation of some other component[s], and it's never changed by other components arbitrarily based only on the variable name.
The use of "dynamic scoping" to describe React Hooks state is unnecessarily imprecise, implying that a fairly well designed system is a specific kind of mess. Please don't engage in FUD.
Tip: Never call setFoo functions from render code. Only call setFoo from event code.
Hooks reveal two major things with React:
1) React developers did not understand the component paradigm that they originally went with. If they did, then they would understand how silly it is that components cannot reuse logic. This was an entire debate many years ago. Composition vs. inheritance. You don't need to throw out classes or objects to get reuse.
2) React developers do not understand functional programming. I could write an entire essay on this. But it should suffice to say, FUNCTIONS DO NOT HAVE STATE. What React hooks introduce has more in common with dynamic scoping, of older LISPs. It fundamentally breaks lexical scoping, which is incredibly important for understanding code flow. You have to be constantly aware of when it's safe to use certain variables and the implications of using variables in certain scopes now. In 2020!! This is INSANE.