I beg to differ here. Or let's say that the React "functional programming" model has very little to do with the actual functional programming done by actual functional programmers. What is true is that React components are functions. But functional programming and programming with functions are two different things.
Second, side effects are just about in every React component where you use a hook.
Third, (hypothesis) `useEffect` is probably a misnomer that stick there because it would be a breaking change to rename it to something more proper.
Words and bickering aside, you can write great applications with React, that's fact. It is also a fact that a lot of folks are using it wrong, which shows either a problem with React learnability itself, or with its documentation, or well, with the programmers themselves.
Hi there. IMO, there are three issues there: familiarity, mental model, and caveats (using $ and not getting reactive updates in some cases).
Focusing on mental model, maybe my mental model can inspire yours? Here it goes.
- For me, `$: dependent variable = expression(independent variables)`, is an equation that Svelte guarantees will hold across the single-file component (SFC). So whenever an independent variable change, the dependent variable is also updated to maintained the equation.
- Caveat: In the statement `$: dependent variable = expression(independent variables)`, the expression language is JavaScript but the semantics of the statement are Svelte's (i.e. *Svelte's* scoping rules apply, not JavaScript's). SvelteScript is so close from JavaScript that it feels intuitive to use but confusing when the two differ. In a poor analogy, just like using a word that means something in French, another in Spanish, and wrongly guessing the source language (hence the meaning) that applies.
Then:
- `$: {some statements here featuring independent variables}`. *Svelte's* scoping rules apply (only the variables visible in the block are targeted by Svelte's reactivity). This is not an equation anymore, it is the expression of an effect triggered by change in dependent variables.
Why this is natural to me? At the specification level, reactive systems are specified with three core syntactic constructs:
1. event -> reaction
2. dependent variable = function (independent variable)
3. dependent variable <- function (independent variables)
The first item means is where you specify what happens when an event occurs. for instance button click -> (counter <- counter + 1; render new counter)
The second item is the same as lambda abstraction. Say `area = f(length, width)`. That's true all the time and allows using `area` everywhere needed instead of `f(length, width)`. But by referential equality rules, you could absolutely do away with `area` - at the expense of course of less clear and more verbose code (and probably less performant too)
The third item is assignment, and is used to describe changes in the state of the component. As a rule, (reaction, new state) = f(event, current state). So the third item describes how to get new state from current state. The first item describes how to get the reaction from the event and current state. The second item is optional but helps a lot readability, conciseness, and performance (not computing `area` twice if you use it twice).
In Svelte syntax:
1 is $: {reaction code here} (event is some change in value of variables scoped in the code)
1 bis: <some html code here> is the same case as 1 with a different syntax when the reaction is a (re)render. Whenever the dependent variables in scope change, a rerender reaction is executed.
2 is $: x = f(a,b,c,...) (Note that the right hand is a single variable name)
3 is any assignment occurring in the SFC.
Not sure if that helps, but well, that's how I stay away from the pitfalls of mixing SvelteScript and JavaScript. Identify events, state variables, the reaction to the events, and the state changes. Then translate that into SvelteScript.
:-) I feel you. I like to think that state machines are used where they are useful (in some games, process orchestration, generators, embedded systems, etc.). The question is more where else can they be useful given that the low hanging fruits have already been harvested.
So far I have to say that it is a mixed experience. There is a cost to the abstraction and the indirection (that is fairly well known easy to describe even if we rarely do so due to some self-imposed no-negativity bias or having some interest in the game), and then there are the benefits that are less easy to describe because they depend highly on the nature of the problem that you are addressing.
I implemented a Medium clone application (https://codebase.show/projects/realworld) with state machines. The result is 47Kb (brought down to 39Kb after compiling the machine and other optimizations) vs. 70Kb for the Vue implementation or 160 KB for the React/Redux one (that implementation piles abstraction over abstraction in the form of libraries and pays the corresponding price). I would count that as benefit. Also cf. https://brucou.github.io/documentation/v1/tutorials/index.ht... for the full pitch.
At this level, you can follow the routing of the app. Every route is a compound state. If you open it, you see the details of the behavior. The full machine (post refactoring) is like this: https://brucou.github.io/documentation/graphs/real-world/rea...
So one advantage is that with those graphs, it is easier to onboard new folks arriving to the codebase. They just have to follow arrows to know what the code is doing in response to a series of inputs.
I could continue but with all that said, the Hyperapp implementation of the same application is 27Kb and also fairly simple (even if arguably not as simple) to get into. So there isn't a clear-cut ex-nihilo benefits to state machines here. In fact if you would have implemented the same application as a MPA instead of a SPA, for most, if not all of the pages, using a state machine to model the behavior is simply overkill. Most of the job and value of the machine in my example is to do the client-side routing done in the machine (so no extra library cost).
Anyways the bottom line is the tool is useful but you have to figure for what, and where is the value maximized. The obvious cases have already been figured out.
Second, side effects are just about in every React component where you use a hook.
Third, (hypothesis) `useEffect` is probably a misnomer that stick there because it would be a breaking change to rename it to something more proper.
Words and bickering aside, you can write great applications with React, that's fact. It is also a fact that a lot of folks are using it wrong, which shows either a problem with React learnability itself, or with its documentation, or well, with the programmers themselves.