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.