6 ms·
The linked article doesn’t convince me, instead it shows a misunderstanding of react and hooks. > But then they added hooks and useState and useEffect and so o
by ojkelly 4y ago
The linked article doesn’t convince me, instead it shows a misunderstanding of react and hooks.
> But then they added hooks and useState and useEffect and so on, which made the functions impure. The problem with hooks is that they “hook into” React state and lifecycle features, which means it is modifying global state.
React components don’t update the dom every time they run, they update the fiber tree / virtual DOM.
Only in the commit phase is the DOM updated and side-effects are run.
My rough understanding is that:
Hooks, excepting useEffect, all run in the render phase.
UseState hooks store data in the component in the fiber tree, and capture a sequential list of updates when you call setState.
Algebraic effects can seem a bit odd at first, but it’s really like a generalised try/catch. Instead of storing state in the function itself, you reach out up the stack to the component and store it there. And every hook you call from your hook stores it there too.
It’s why call order is important, because it’s how they know which is which.
You don’t modify any global state though.
The actual component function needs to be able to be called multiple times in the render phase (which just updates the vdom), and must have the same output each time, if the inputs/props are the same.
Every now and then, the tender phase can be interrupted to run the commit phase, which synchronously brakes a snapshot of the vdom and applies all the needed updates to the outside world.
Perhaps it’s better to think of as
render: f(props) -> descriptionOfUI
commit: apply(descriptionOfUI)
I would absolutely say components and hooks are functional, with algebraic effects. And that the resulting data struct from those components, is what’s used to produce side effects.
Even useEffect, is a description of a side effect to run, it doesn’t run in your hook, it runs on commit with all the other side effects.
There’s a ton of optimisations under the hood but that’s roughly my understanding of how it works.
- petilon 4y ago> ...and capture a sequential list of updates when you call setState. In functional programming, functions are not allowed to do that. The only thing a function is allowed to do is return a value. > ...you reach out up the stack to the component and store it there. FP functions are not allowed to do that. In FP functions can only rely on the parameters passed to it (it cannot refer to anything outside) and it should not do anything beyond return a value. > It’s why call order is important, because it’s how they know which is which In FP, functions can be called in any order (unless one function needs the return value of another), and the final result is not affected by the order. > You don’t modify any global state though. If you have state it is not FP, whether it is global or not.
- javcasas 4y ago> In functional programming, functions are not allowed to do that. The only thing a function is allowed to do is return a value. Oh, yes, they are allowed to do that. You capture the effects into a list, and return the tuple of list and return value. If you feel like it, you wrap that into a monad to pretend you are only "returning" a single thing. > In FP functions can only rely on the parameters passed to it (it cannot refer to anything outside) and it should not do anything beyond return a value. You mean explicit parameters (props) and implicit parameters (context), right? I thing you forgot the latter. Implicit parameters have existed for quite a bit, for example in the reader monad. > In FP, functions can be called in any order (unless one function needs the return value of another), and the final result is not affected by the order. Yup, except if you write a bunch of functions and store them in a list with the intention of applying the result of the first entry of the list against the first entry of the list. Now, if you construct the list of functions as effects (by hiding them behind a monad) you find out that you need to call the effects in the same order as to construct the list of effects in the same order. This doesn't contradict FP, it contradicts your mental model of how React is supposed to work. > If you have state it is not FP, whether it is global or not. The state resides in the runtime executor, exactly like Haskell's IO monad. Again, this contradicts your mental model, not React or FP.
- petilon 4y agoI think you may be missing the forest for the trees. The point of FP is that you can glance at a function and say 'this is obviously correct' without having to work out the state and context of every call.