Goodbye, useEffect: David Khourshid

preview_player
Показать описание

Goodbye, useEffect
From fetching data to fighting with imperative APIs, side effects are one of the biggest sources of frustration in web app development. And let’s be honest, putting everything in useEffect hooks doesn’t help much. Thankfully, there is a science (well, math) to side effects, formalized in state machines and statecharts, that can help us visually model and understand how to declaratively orchestrate effects, no matter how complex they get. In this talk, we’ll ditch the useEffect hook and discover how these computer science principles can be used to simplify effects in our React apps.

Aboud David Khourshid
David is a software engineer who loves playing piano and is passionate about animations, state machines, cutting-edge user interfaces, and open-source. Previously at Microsoft, he is now the founder of Stately, a startup focused on making even the most complex application logic visual and accessible to developers and non-developers alike.

Рекомендации по теме
Комментарии
Автор

Great explanation. A bit unrelated but that font is a bit confusing at first glance, parentheses looks like square brackets.

gastonfernandorosso
Автор

I would love to see a more real world example of this. Even a smaller "dashboard" app with 2-3 different pages would be enough. I've gotten so used to data fetching in useEffect that it's hard to get rid of it mentally. I also don't use state management libraries or data fetching libraries 99% of the time because for most cases I work on, I've seen that I don't really require them.

To be honest, if I didn't do data fetching in useEffect, I would barely use that hook considering that API calls are main things I usually put in useEffect.

randmtv
Автор

The real valuable takeaway here IMO is this reducer design pattern (15:02):
Changing your reducer from this:
(state, action) -> nextState
To this:
(state, action) -> [nextState, effectsData]


Typical reducer usage is getting that nextState and then calling setState(nextState) to run the React render.

Now, in addition to next state the reducer also provides data that describes any effects that should happen (e.g. an API request)
So before you call setState(nextState), you should process any effects based on that data (e.g. performing a fetch)

Your top level app function could look something like this:

let state = ...initial state...
function runMyApp(action) {
let [nextState, effectsData] = myAppReducer(state, action)

...process any effects (e.g. performing fetch)...

state = nextState
yourReactUI.setState(state)
}

Then in your react components, all your event handlers do is dispatch actions to this top level function.

Any event callbacks, e.g. a fetch request callback, can also dispatch actions to this top level function.

A simple example for some data that describes an effect: {type: "apiRequest", id: 123, method: "get", url: "users"}
Upon your reducer returning this data, you can do something like the following:
fetch(url).then(response => response.json()).then(data => runMyApp({ ... build action from data ... }))

React components aren't the only things that can dispatch actions to your top level function. You can dispatch in pretty much any callback listening to any event.

Personally I like to make a distinction between pure (underivable) state, derived state, and ui props (for React components)
Like so:

let state = ...initial state...
let derivedState = null //optional, for performance reasons only
function runMyApp(action) {
let [
nextState,
nextDerivedState,
effectsData
] = updateMyApp(state, derivedState, action) <-- top-level "reducer"


if (effectsData.type === "apiRequest") {
fetch...then(data => runMyApp(createAction(data)))
}
...process other effects...

state = nextState
derivedState = nextDerivedState

//UI props are just part of the derived state
}

This is basically how I design all my software applications -- web, mobile, and desktop apps -- regardless of language or technology.

jtmv
Автор

Man just made me go in and replace our in house React templates to use Suspense instead of useEffect wrappers for async calls. Enjoyed the whole process!

DrMarmalader
Автор

Definitely learned some things about useEffect in React 18 that I wasn't aware of. Really appreciate this, except that I'll have to go into work and tomorrow clean up some places that I'm sure I've misused that hook. Damn.

adamploof
Автор

I love how this is an absolute cluster fuck. Only use useEffect for this, well and sometimes this, but not for this cause that's bad. Use these things for the other stuff, except for when your doing it this way, then do it the other way but not that way because that's bad. Got it? Cool. I hope everyone does it the right way now!!

otockian
Автор

People forget that you can use several useEffects, each one with a different dependency array.

rael_gc
Автор

I'll use vue for the next project, thanks!

Lgg
Автор

Ever since I started using Svelte I realized that the next step in frontend technologies are JS compilers and that all other frameworks are just nice attempts but not the right solution. This video just shows how much

DeadalusX
Автор

The useEffect + useRef combo seems like a pretty good solution. I'd just wrap that logic in a custom useOnMountEffect hook as a drop in replacement for on-mount useEffect usages and call it a day. Putting side effect in event handlers when possible also seems like a good direction to go.

ekillops
Автор

Someone needs to tell him that the square and curved brackets/parenthesis look exactly the same in this font.

omri
Автор

I prefer to keep with useEffect, this presentation is like a creepy movie that turned useEffect solution into a Fred Kruger of state sync, the simple is better 👍

MsVsmaster
Автор

My brother in Christ, what is that font?

prathikshputtur
Автор

It just seemed to me that the talk is a veiled dissatisfaction with React due to misunderstanding than a real problem with useEffect?

theextreme
Автор

Am I the only one getting the angular vibe from this guy?

deepfuchsia
Автор

26 minutes talk, yet only described a problem of useEffect that is written in the docs, just called to do something, no real solution, nothing
I could present a masters degree project twice in 26 mins
And the talk is complete mess jumping from topic to topic

alexsherzhukov
Автор

I don't understand how useEffect + useRef escape hatch works if React does unmount + remount. The ref should also be re-initialized to "false" when you unmount a component, so it will be false.
Unless, React 18 StrictMode or concurrency logic does a different unmount-remount logic ( lets call it shallow-remount :D ). If you unmount a component useState, useRef etc. everything inside a component should reset.

cmlttnts
Автор

Interesting talk, I don't personally have any issues with useEffect, in fact I think the combo with custom hooks is a fantastic paradigm.

The examples given seemed contrived or explained in a way that presents them as overly complex. I'd say that most logic can be abstracted to custom hooks anyway if the code becomes too cumbersome or ugly.

So I wasn't convinced but I enjoyed the talk none the less.

nazzanuk
Автор

Nice talk though most examples were just incomplete, important parts of code were missing. I wanted to see a real example and a full implementation how useEffect and/or react-query is replaced with the mentioned approach.

faraonch
Автор

... wat? why does React have to be so complicated. When he talks about what we should do instead of useEffect he whips out this enormous useCallback reducer contraption and my brain just melted. Vue is so much easier

ChrisHaupt