Goodbye, useEffect - David Khourshid

BeJS
16 Nov 202229:58

Summary

TLDRThe speaker delivers an in-depth tutorial on the proper use of React's useEffect hook, emphasizing its purpose for synchronization rather than as a lifecycle hook. They address common misconceptions, illustrate the pitfalls of misuse, and provide guidance on alternative approaches for handling side effects, such as using event handlers for 'fire and forget' actions and leveraging new hooks like useSyncExternalStore for subscriptions. The talk concludes with a live demonstration of utilizing state machines for effect management, showcasing a simplified and efficient way to handle complex component behaviors in React.

Takeaways

  • 🌟 The speaker emphasizes the importance of using `useEffect` correctly, highlighting that many developers struggle with it, even at a senior level.
  • 🔄 React 18 introduces changes that can cause effects to run twice on mount in strict mode, which can be confusing and needs to be managed properly.
  • 🤔 The speaker suggests that `useEffect` should be thought of as a synchronization tool rather than a lifecycle hook, aligning with the mental model proposed by Dan Abramov.
  • 🚫 It's advised against using `useEffect` for transforming data, communicating with parents, or subscribing to external stores, as there are better alternatives.
  • 📈 The script discusses the misuse of `useEffect` for fetching data, recommending instead to render as you fetch using libraries like React Query or framework-specific solutions.
  • 🛑 The speaker warns against setting state inside `useEffect`, as it can lead to infinite loops and performance issues.
  • 🔍 The script highlights the new React documentation at beta.reactjs.org as a valuable resource for understanding the proper use of `useEffect` and other hooks.
  • 📚 The speaker introduces the concept of using state machines to model effects, making the logic clearer and more maintainable.
  • 🔌 The script mentions `useSyncExternalStore` as a powerful hook for subscribing to external stores in a more efficient and less error-prone way.
  • 🎯 The speaker concludes by summarizing that `useEffect` is for synchronization, state transitions trigger effects, and action effects should be handled in event handlers.

Q & A

  • What is the main focus of the talk at React Brussels?

    -The main focus of the talk is to provide a crash course on the correct usage of the useEffect hook in React, and to address common issues and misconceptions about it.

  • Why might a React developer struggle with useEffect?

    -A developer might struggle with useEffect due to its complexity, especially when dealing with large dependency arrays, conditional statements, and issues arising from React 18's behavior of running effects twice on mount in strict mode.

  • What is the 'frustrated react developer Smiley' mentioned in the script?

    -The 'frustrated react developer Smiley' is a humorous reference to the common struggles developers face when dealing with complex or confusing aspects of React, such as the useEffect hook.

  • What is the difference between 'fire and forget' effects and synchronized effects in React?

    -Fire and forget effects are those where the result of the effect is not important, like a console log or an analytics call. Synchronized effects, on the other hand, involve communication with an external system and may be long-lived, requiring synchronization with the component's state.

  • Why should you avoid setting state inside useEffect?

    -Setting state inside useEffect can lead to unexpected behavior and potential infinite loops, especially when the state update triggers the effect again, creating a cycle of state changes and effect executions.

  • What is the correct mental model for understanding useEffect according to the talk?

    -The correct mental model for understanding useEffect is 'synchronization' rather than 'lifecycle'. It should be used to synchronize the component's state with external changes or side effects that are not directly related to the component's rendering.

  • What is the purpose of the 'use sync external store' hook mentioned in the script?

    -The 'use sync external store' hook is used for subscribing to external data stores. It simplifies the process of subscribing, reading, and unsubscribing from an external store, making it easier to manage state that comes from outside the React component.

  • Why is 'render-as-you-fetch' considered a better approach than using useEffect for fetching data?

    -'Render-as-you-fetch' is considered better because it allows the component to render immediately with the fetched data, avoiding unnecessary re-renders and complexity associated with managing promises and cancellation inside useEffect.

  • What are some alternative solutions to using useEffect for fetching data?

    -Alternative solutions include using framework-specific solutions like Remix's loader functions, Next.js's getServerSideProps, or third-party libraries like React Query, which are designed to handle data fetching and caching more efficiently.

  • What is the 'use' hook mentioned in the script, and what does it offer?

    -The 'use' hook, which is part of an RFC for first-class support for promises and async, is a new approach that might become the future of using suspense inside of React. It allows components to automatically suspend when data is being fetched, providing a more streamlined way to handle asynchronous data.

  • How can state machines be used to model effects in React components?

    -State machines can be used to model effects by defining state transitions and associating effects with those transitions. This approach helps visualize and reason about the component's behavior, making it easier to understand when and how effects should be triggered.

Outlines

00:00

📚 Introduction to Effective Use of React's useEffect Hook

The speaker begins with a warm welcome to the React Brussels audience, expressing excitement about being back in Belgium. They set the stage for a crash course on the proper use of React's useEffect hook, aiming to eliminate confusion and unnecessary use of useEffect in applications. The speaker acknowledges the challenges even senior developers face with useEffect and reassures the audience that struggles are common in building complex React applications. They introduce the topic by discussing the typical problems that arise with useEffect, especially with the introduction of React 18, which can cause effects to run twice on mount in strict mode. The speaker emphasizes that useEffect is not a lifecycle hook and should be thought of in terms of synchronization rather than lifecycle events.

05:00

🔧 The Evolution and Misuse of useEffect

This paragraph delves into the evolution of effects in React, from class components with componentDidMount, componentDidUpdate, and componentWillUnmount to the functional approach with hooks. The speaker critiques the common misuse of useEffect, which often results in complex and hard-to-maintain code, especially as applications grow. They discuss the issues that arise from trying to control the 'fire hose' of changes in a React application, leading to tangled and confusing useEffect dependencies and conditionals. The paragraph highlights the problems that React 18's strict mode brings to light, forcing developers to reconsider their use of useEffect and prompting a reevaluation of the mental model for effects in React.

10:01

🚀 useEffect for Synchronization, Not Just Effects

The speaker clarifies that useEffect is intended for synchronization, distinguishing it from 'fire and forget' effects like logging or analytics calls that don't require a response. They use the example of synchronizing with an external API, where the effect is long-lived and can safely remount and unmount as the state changes. The React documentation is referenced to differentiate between effects and event handlers, with the former being long-lived and the latter being short-lived actions. The speaker emphasizes the importance of using useEffect for synchronization with external systems rather than for one-off actions.

15:01

🛑 Avoiding Common Pitfalls with useEffect

The paragraph discusses common pitfalls with useEffect, such as setting state within an effect, which can lead to infinite loops and performance issues. It advises against using useEffect for data transformation, communication with parent components, and subscribing to external stores, suggesting better alternatives for each case. The speaker introduces 'use-sync-external-store' as a hook that simplifies subscription logic and mentions the benefits of render-as-you-fetch patterns for data fetching, as opposed to using useEffect. They also touch on the upcoming 'use' hook, which aims to provide first-class support for promises and asynchronous operations in React.

20:02

🔄 Refactoring useEffect to Improve Code Clarity

The speaker provides guidance on refactoring code to avoid unnecessary useEffect hooks. They demonstrate how to move logic related to user events and state changes into event handlers or separate hooks, which can improve code clarity and maintainability. The paragraph includes a live demo of a video player component, showing how to use a state machine approach to handle complex logic involving video playback, closing behavior, and user interactions. The speaker emphasizes the importance of modeling effects with state transitions and event handling for better declarative code.

25:03

🎉 Conclusion: Best Practices for useEffect and Event Handling

In conclusion, the speaker summarizes the best practices for using React's useEffect and handling events. They reiterate that useEffect is for synchronization, not all effects, and that state transitions should trigger effects, while action effects belong in event handlers. The speaker also highlights the importance of render-as-you-fetch strategies and introduces stately.ai studio, a new tool for modeling state transitions and effects. The talk ends with an encouragement for the audience to explore these best practices and the new tools available to simplify React application development.

Mindmap

Keywords

💡useEffect

useEffect is a React Hook used for performing side effects in functional components. It allows you to synchronize a component with an external system or perform actions in response to state changes. In the video, the speaker discusses the common misuse of useEffect and how it can lead to confusion and bugs, especially with the introduction of React 18. The speaker emphasizes that useEffect is not a lifecycle hook and should be used for synchronization rather than as a general-purpose side effect handler.

💡dependency array

In React, the dependency array is a feature of the useEffect Hook that determines when the effect should re-run. It should contain all values that the effect depends on. The video script mentions the complexity that can arise from managing dependency arrays, especially as applications grow. The speaker suggests that the dependency array can be a source of confusion and bugs, and encourages developers to rethink their approach to using effects.

💡synchronization

Synchronization in the context of React refers to keeping the component state in sync with external data sources or system states. The speaker in the video emphasizes that useEffect is primarily for synchronization, such as subscribing to an external API or managing subscriptions. This is contrasted with 'fire and forget' effects, which do not need to be synchronized with the component's state.

💡lifecycle hooks

Lifecycle hooks in React are methods that are called at specific points during a component's lifecycle, such as componentDidMount, componentDidUpdate, and componentWillUnmount. The video script clarifies that useEffect is not a lifecycle hook, despite being used around component mount, update, and unmount. The speaker argues for a shift in thinking from lifecycle to synchronization for useEffect.

💡declarative vs imperative

Declarative programming is about describing what the program should accomplish, while imperative programming is about describing how to accomplish it. In the video, the speaker discusses how React is a declarative framework but that the use of useEffect can sometimes feel imperative due to its complexity. The speaker prefers an imperative approach for clarity and simplicity, especially when dealing with side effects.

💡React 18

React 18 is a major version of React that introduced significant changes, including improved performance and new features. The video script mentions that React 18 can cause useEffect to run twice on mount in strict mode, which can lead to bugs if not handled correctly. This change is part of React's strategy to encourage better practices with useEffect.

💡useSyncExternalStore

useSyncExternalStore is a React Hook introduced in the video script as a way to subscribe to external data stores. It simplifies the process of keeping a component's state in sync with an external source, which is traditionally managed through useEffect. The speaker uses this hook as an example of a more straightforward way to handle external subscriptions.

💡action effects

Action effects, as discussed in the video, are side effects that are triggered by user actions, such as form submissions or button clicks. The speaker suggests that these effects should be handled inside event handlers rather than in useEffect, to maintain clarity and avoid unnecessary complexity.

💡render as you fetch

Render as you fetch is a pattern where data fetching is performed as part of the rendering process, rather than in useEffect. The video script argues that this approach is more straightforward and avoids the pitfalls associated with using useEffect for data fetching, such as race conditions and unnecessary re-renders.

💡useState

useState is a React Hook used for adding state to functional components. The video script mentions useState in the context of setting state within useEffect, which can lead to infinite loops and performance issues. The speaker advises against using setState inside useEffect and recommends handling state changes more directly in the component or using other Hooks.

💡useMemo

useMemo is a React Hook used for optimizing performance by memoizing expensive calculations. The video script discusses useMemo in the context of calculating derived state, suggesting that it should be used sparingly and only when necessary to avoid unnecessary performance overhead.

Highlights

Introduction to the crash course on the correct use of React's useEffect hook.

The speaker's enthusiasm about being back in Belgium and the React Brussels event.

The common struggle with useEffect even among senior React developers due to its complexity.

The misconception that useEffect is a lifecycle hook, when it's actually about synchronization.

React 18's behavior of running effects twice on mount in strict mode and how it affects existing useEffect implementations.

The difference between fire and forget effects and synchronized effects in the context of React.

The recommendation to avoid using useEffect for transforming data or calculating derived state, suggesting useMemo or direct function calls instead.

The pitfalls of setting state within useEffect and the potential for infinite loops.

Advice against using useEffect for communicating with parent components to prevent unnecessary re-renders.

Introduction of useSyncExternalStore for subscribing to external stores, as an alternative to useEffect.

The argument against using useEffect for fetching data, promoting render-as-you-fetch patterns instead.

The announcement and explanation of the new useJustUse hook for handling promises and async operations.

The recommendation to move action effects to event handlers rather than useEffect for clarity and simplicity.

The use of state machines for modeling effects and state transitions, providing a visual and intuitive way to understand complex logic.

Live coding demonstration of using state machines to handle complex video player logic in React.

The release of stately.ai studio and the introduction of its v1.0, offering tools for state management and effect handling.

Final summary emphasizing the correct use cases for useEffect, the role of state transitions in triggering effects, and the placement of action effects in event handlers.

Transcripts

play00:01

all right

play00:03

all right hello everyone hello react

play00:05

Brussels it's been many years since I've

play00:07

been in Belgium so I'm so glad to be

play00:10

back here again this is basically going

play00:12

to be a crash course where we are going

play00:13

to learn the right way to use effect and

play00:16

saying goodbye to all of the other use

play00:18

effects that we really don't need in our

play00:21

application so buckle up we are we are

play00:24

in for a ride hopefully you will learn a

play00:26

lot of things today but first of all I'm

play00:29

extremely happy to be here who's happy

play00:31

to be here at reacts Brussels yeah

play00:34

all right

play00:35

who's uh who's a little sad that you

play00:38

know it's it's ending so soon I mean we

play00:40

we had we had a lot of amazing talks

play00:43

like some of my favorite talks today uh

play00:46

how many of you feel like this have you

play00:49

seen this smiley before this is the

play00:51

frustrated react developer Smiley so

play00:55

yeah

play00:57

so of course

play01:01

take care

play01:04

now I I learned hooks I um I I was

play01:08

actually fortunate enough to get a

play01:09

preview of hooks when they first came

play01:11

out and they all looked really

play01:12

interesting except use effect I'm like

play01:14

all right that's gonna be an interesting

play01:15

one and then uh you know people started

play01:18

saying okay use the fact I have an

play01:20

effect this is where it goes but then

play01:23

the problems kept creeping up and I'm

play01:25

sure in your code bases if you're using

play01:27

react uh you know you might have some

play01:30

really nasty use effects in there

play01:32

but if you're struggling with use

play01:33

effects don't worry even senior react

play01:36

developers struggle with it if anyone

play01:38

tells you otherwise they're not making

play01:40

you know good enough react applications

play01:42

because you do need use effects in your

play01:45

application and you might have this big

play01:47

nasty dependency array and if statements

play01:50

it's all very typical it's just a really

play01:53

awkward hook all right

play01:55

so uh typically this is what our you

play01:59

know use effects looks like we have a

play02:01

use effect that does something we have a

play02:03

cleanup dependencies all is fine you

play02:06

know it might have worked before but

play02:09

then guess what react 18 came out

play02:12

and it rendered this again so it ran the

play02:14

effects twice on Mount in straight mode

play02:17

how many of you have actually ran into

play02:19

that or is that just a me problem okay a

play02:22

bunch of you

play02:23

so uh use the fact if I were to

play02:26

summarize this talking just one slide

play02:29

it's not for all effects in fact I would

play02:32

say it's even confusingly named it

play02:34

shouldn't be used effect it should be

play02:36

used synchronized but we're going to be

play02:38

talking about that in a minute so what

play02:40

was life before like before use effects

play02:43

well we had component did Mount

play02:45

component did update and component will

play02:47

unmount and these were all convenient

play02:50

places to put your effects especially

play02:52

the effects that were long lived inside

play02:54

of your class-based react components and

play02:57

so when we moved to hooks thankfully uh

play03:00

we we need to figure out okay I have

play03:02

these please these effects in my life

play03:04

cycle hooks so where do they go now well

play03:07

we put all of our componented mounts

play03:09

effects inside of this one with an empty

play03:12

dependency array we put the ones where

play03:14

it happened on component did update in a

play03:18

non-empty dependency arrayed use effects

play03:21

and then this awkward looking uh

play03:24

component will unmount it goes in use

play03:26

effects with this return function and

play03:29

this just looks really really awkward so

play03:31

I want to say first and foremost that

play03:34

use effect is not a life cycle hook and

play03:37

while you could use it that way and it

play03:39

is expected to run at the exact same

play03:42

time as you mount your component

play03:43

unmounts and change it's not the way

play03:45

that you should be thinking about things

play03:47

uh Danny abramov even said that the

play03:49

mental model of use effect is

play03:51

synchronization not life cycle and so

play03:54

we're going to be talking about why

play03:56

exactly that is

play03:58

all right so uh you know we have our use

play04:01

effects we have the effect in there

play04:03

we're doing something and the dependency

play04:05

array it's uh you know this is when that

play04:08

effect is going to be executed now react

play04:11

is supposed to be this declarative

play04:12

framework but honestly this might feel

play04:15

like okay we're doing our effects in a

play04:17

declarative way but in reality there is

play04:20

a ton of indirection over here so take

play04:23

the imperative approach first like when

play04:25

something happens like an event or you

play04:29

know something else a button is pushed a

play04:31

form is submitted execute this effect

play04:34

you might be looking at this and saying

play04:36

okay that's the imperative approach

play04:38

the declarative approach with use effect

play04:40

looks more like this when something

play04:42

happens and uh you know it causes the

play04:45

state to change then depending on which

play04:48

parts of that state change which is the

play04:50

dependency array this effect should be

play04:52

executed see how it's more declarative

play04:54

right but only if some condition is true

play04:57

inside of my use effects also reacts May

play05:00

execute it again for some future reason

play05:02

but only in strict mode which you

play05:05

shouldn't disable for some future reason

play05:07

so I mean honestly whatever your opinion

play05:11

is on imperative versus declarative I

play05:14

prefer the imperative approach and you

play05:17

could express it in this imperative

play05:19

approach in a declarative way we'll be

play05:21

talking about that later too

play05:23

but some of you might be thinking you

play05:25

know what I didn't really have a problem

play05:27

with use effects like I just do

play05:29

something I return a cleanup and I put

play05:32

things in my dependency array everything

play05:34

is fine but the more you add features

play05:38

and and changes to your application your

play05:40

use effects start to look more like this

play05:43

where we have a bigger dependency array

play05:46

we have multiple use effects we forget

play05:48

the cleanup and we have this nasty

play05:51

conditional in here and we're doing

play05:53

things depending on what's inside there

play05:55

so we're trying to control the fire hose

play05:57

of changes happening so that our effects

play06:00

happens at exactly the right time and

play06:03

I've seen this code all over the place

play06:04

I've searched Source graph for examples

play06:07

and there's just plenty of examples this

play06:10

is a particularly nasty one and so it

play06:13

really uh it really showed me that

play06:16

dependencies are really the wrong mental

play06:18

model for effects we want effects to

play06:20

execute when things happen not exactly

play06:23

when things change so let's get back to

play06:26

the original issue react 18 running

play06:29

effects twice on mounts in strict mode

play06:31

how do we fix this in first of all why

play06:34

does this happen so

play06:36

react is actually doing this on purpose

play06:39

behind the scenes it's not a bug or

play06:41

anything it's mounting the components

play06:43

and then it's doing a simulated unmount

play06:45

of that component which is calling the

play06:47

cleanup of the effect and immediately

play06:49

afterwards it's remounting uh the effect

play06:52

so

play06:54

um you get your double execution of the

play06:55

effects and so uh you know when I first

play06:58

ran into this I was like this is a bad

play07:01

hook it's use defect you know it feels

play07:04

like a major major foot gun but honestly

play07:07

this was reacts way at least react to

play07:10

18's way of telling you hey you're using

play07:13

the use effect hook wrong so what is use

play07:16

effects for it's for synchronization and

play07:19

so there's a difference between fire and

play07:22

forget effects and synchronizing

play07:24

something in your component with some

play07:26

outside source

play07:28

so uh take this example we're

play07:31

synchronizing with some external API

play07:33

some story API so that uh whenever the

play07:36

item changes we're we're getting this

play07:40

item data and we return an uh an

play07:43

unsubscribe function and this is going

play07:46

to change whenever our item changes

play07:48

because we need to unsubscribe to the

play07:50

old item and re-subscribe to the new

play07:52

item now doing something like this means

play07:55

because you're just keeping track of

play07:57

some external thing we could unsubscribe

play07:59

and resubscribe multiple times it

play08:02

doesn't matter it's like watching TV if

play08:04

you put on the news you could turn the

play08:06

TV on and off you could change channels

play08:09

you could go back to the previous

play08:10

channel that news channel is still going

play08:12

to be the same so that's sort of the

play08:15

mental model that you should be thinking

play08:16

of with use effects

play08:19

um the react documentation distinguishes

play08:22

between effects and event handlers so uh

play08:26

when react is talking about effects with

play08:29

the capital E they're talking about

play08:30

long-lived effects so these

play08:32

subscriptions that I'm talking about

play08:34

when uh we're talking about fire and

play08:36

forget effects uh reacts in the docs

play08:39

mentions that as event handlers so

play08:42

here's the difference a fire and forget

play08:44

effect you don't care what the results

play08:46

of this could be a console log an

play08:48

analytics call maybe you're sending some

play08:51

data asynchronously but you're not

play08:53

awaiting a response a synchronized

play08:55

effect is when you're actually

play08:57

communicating with an external system so

play09:00

this effect could actually be long-lived

play09:02

and so that's why it's fine for it to

play09:04

unmount and remounts because just like

play09:07

changing channels on the TV you are just

play09:09

changing

play09:11

um you know like you're changing the

play09:13

subscription but you still get the same

play09:14

values

play09:16

okay so where exactly do the action

play09:19

effects those fire and forget effects

play09:21

where exactly do those go

play09:24

we know that you know we shouldn't

play09:25

really be putting side effects in render

play09:27

even though in some instances it's

play09:29

actually okay but let's just assume that

play09:32

you can't do that

play09:33

and we already know by now hopefully

play09:36

that putting it in use effect is awkward

play09:38

so where where else do we have space in

play09:41

this function to put it and don't say

play09:43

the gap between that because I just

play09:45

forgot to fill that in

play09:47

outside the component Maybe

play09:49

let's explore this

play09:51

so when we um when we mentioned that

play09:55

that the um that use effect is going to

play09:58

run twice when you mount a component

play10:00

here's what's happening we're attaching

play10:03

that effect to the components mounting

play10:05

and unmounting so when an event handler

play10:08

causes a state change that is going to

play10:11

cause the components to re-render but

play10:13

also remember that react can remount

play10:16

that component and so this effect might

play10:19

be executing multiple times so if we put

play10:22

it outside of the render say over here

play10:24

it doesn't matter how many times that

play10:26

component's unmounts and remounts and

play10:29

how often react re-executes that use

play10:32

effect the effects that we put outside

play10:35

of the component rendering and outside

play10:37

of use effect is only going to be

play10:39

executed once so these action event

play10:42

effects should actually happen outside

play10:45

of rendering

play10:46

so then where exactly do action effects

play10:48

go inside of event handlers at least

play10:51

sort of so we have this submit data

play10:54

inside of this form on submit event

play10:56

handler and this is actually going to be

play10:59

a much better pattern than trying to do

play11:01

this in the use effect and we're going

play11:03

to see an example of this shortly

play11:05

so by doing it this way you have this

play11:09

pattern of when an event happens in

play11:12

effect is executed

play11:14

and so uh if you do it using use effects

play11:17

then this is the mental model when an

play11:20

effect happens you're changing some

play11:22

states which can trigger an effect

play11:24

because that effect is listening for a

play11:27

state change and especially if you have

play11:28

multiple use effects other states may

play11:31

change and you get a chain of triggered

play11:34

State changes which might trigger

play11:36

another effect and this becomes really

play11:39

really hard to visualize really hard to

play11:41

think about

play11:43

all right so everything I'm going to

play11:45

explain including when to execute action

play11:48

effects and uh when to use use effects

play11:52

this is all actually explained in the

play11:54

new react docs at

play11:57

beta.reactsjs.org uh when I first

play11:59

started giving a talk like this these

play12:02

actually did not exist so I'm actually

play12:04

really thankful if you go to the normal

play12:06

reacts.js.org documentation site they

play12:09

have a nice Banner on top that points

play12:10

you to

play12:12

beta.react.js.org I Really encourage you

play12:14

to visit it because there's a lot of

play12:16

great information in there and one of my

play12:18

favorite sections is you might not need

play12:21

an effect so I'm going to explain to you

play12:25

all of the different points that they

play12:26

make

play12:27

first one

play12:29

is you don't need a use effect for

play12:31

transforming data I mentioned use memo

play12:35

gear you don't even have to use memo so

play12:37

let's take this example we have a cart

play12:39

we're keeping track of the items we're

play12:41

keeping track of the total and so

play12:43

whenever the items change we have to

play12:45

update the total right your first

play12:47

thought might be okay that's an effect

play12:49

when items change set the total to the

play12:53

new number of items but guess what you

play12:56

could do this directly

play12:58

inside of the uh inside the function so

play13:01

a derived value is just you're reducing

play13:05

the items or if you don't want to use

play13:06

reduce you could have a function that

play13:08

just calculates the total price but you

play13:10

could do it directly inside of the

play13:11

components and if this is an expensive

play13:14

operation and only if it's an expensive

play13:16

operation you could take this and you

play13:18

could put it inside of a used memo if

play13:21

you really want to don't overload your

play13:24

components with use memo because uh You

play13:27

Know You're basically trading

play13:28

performance for memory and yeah only use

play13:32

this when you really need to when you

play13:33

have expensive calculations but yeah you

play13:36

don't need use effects to calculate

play13:38

derived State and I actually ran into

play13:41

this problem like basically whenever you

play13:43

see a set State inside of a use effect

play13:45

it should be sort of a warning sign to

play13:48

you especially if this happens I've had

play13:52

this happen before I've had it happen

play13:54

with a fetch which is really terrible

play13:56

because you know that makes a million

play13:58

API calls so much that react has

play14:00

actually had to add a warning saying

play14:03

like hey this is rendering a thousand

play14:05

times and you're probably doing

play14:07

something wrong and so that's why you

play14:09

know some people think that the default

play14:11

behavior of use effect is an infinite

play14:13

Loop but this is now mentioned in the

play14:16

beta docs that this is actually a

play14:17

pitfall and you should not be setting

play14:20

States or at least you should avoid

play14:22

sending State inside of use effect and

play14:24

also don't forget that dependency array

play14:26

it's extremely important

play14:28

all right second thing you don't need

play14:31

use effects for communicating with

play14:33

parents so sometimes we have this

play14:36

pattern where we have on open and on

play14:38

closed in the parents and so depending

play14:41

on the state of something we are calling

play14:43

on open or on close uh so the problem

play14:46

with this is that you you might be

play14:48

accidentally introducing additional

play14:50

renders because uh the use effects

play14:53

because of a state change

play14:55

it's re-rendering and then it is in the

play14:58

next um the next cycle like when use

play15:01

effect is called it is telling the

play15:03

parents to do something which might tell

play15:04

the component to do something so you

play15:06

might be introducing additional

play15:07

re-renders inside of there so a better

play15:10

pattern to do is move these effects like

play15:14

on open on closed so these fire and

play15:16

forget effects move them closer to where

play15:18

the state change actually happens so I'm

play15:21

calculating if it's going to be open or

play15:23

if it's going to be closed I'm keeping

play15:25

track of state which I might not

play15:27

actually need to do here and then

play15:29

depending on whether it's open or closed

play15:31

I called directly in the event handler

play15:34

this toggle view event handler on open

play15:37

or on closed

play15:39

and you could have also when you do that

play15:42

you could easily refactor it to a

play15:44

separate hook and then you have this

play15:46

nice used toggle hook that you could

play15:48

just use directly in your component it's

play15:50

a much much simpler way to uh to express

play15:53

that logic and to contain it in a in a

play15:57

in a hook

play16:00

all right so third thing you don't need

play16:02

use effects for subscribing to external

play16:05

stores so I know what you're thinking

play16:07

like I just said that this is the one

play16:10

thing that you should use use effect for

play16:12

and it is true most of the time however

play16:14

there is a really cool hook that was

play16:16

mentioned in the last Talk use sync

play16:18

external store and um you might think

play16:20

okay that's a very complicated sounding

play16:22

hook and it seems like it's for advanced

play16:24

use cases for Library authors but it

play16:26

actually makes things a lot simpler so

play16:28

going back to a previous example where

play16:30

we're subscribing to a story API I'm

play16:33

checking for the connection status and

play16:36

I'm setting is connected which again if

play16:38

you're setting State over here it might

play16:40

be a warning sign that you might be able

play16:43

to refactor out this used effect and so

play16:46

I'm subscribing to it that I'm calling

play16:48

unsubscribe and I'm reading data from

play16:51

this uh store API so instead of doing

play16:54

this

play16:55

I could use the use sync external store

play16:57

hook and it actually makes things a lot

play16:59

simpler because we're getting is

play17:01

connected from this snapshot over here

play17:04

this door API dot get status and we're

play17:07

reading whether it's connected or not so

play17:09

this is going to be a Boolean we pass in

play17:12

the subscription function or the

play17:14

function that will actually subscribe to

play17:15

the store and we also provide the server

play17:18

snapshots so this could run uh on server

play17:21

side rendering

play17:23

all right this one is actually a big one

play17:25

because this accounts to like so many of

play17:29

my previous uses of use effect which is

play17:32

fetching data we think okay I need to

play17:35

fetch data I need to call an API so I'm

play17:37

just going to stick it in the in an

play17:39

effect but the better way to do this is

play17:41

actually render as you fetch so here's

play17:45

an example you all have probably seen

play17:47

this a hundred times where we have to do

play17:50

this weird dance of uh having a

play17:52

cancellation flag and then we get our

play17:54

items and you know if it's canceled so

play17:56

if we navigate away or we don't want to

play17:59

call This Promise anymore we're going to

play18:01

ignore the response from that promise

play18:03

and then we set the item switch again if

play18:05

you see this in the use effect it's a

play18:07

warning sign and then we return this

play18:09

cleanup where if anything changes is

play18:12

canceled is true also I forgot the

play18:15

dependency array I legitimately forgot

play18:16

it I just realized that now so this is a

play18:19

very very bad use effect

play18:21

all right so what are some Alternatives

play18:23

well uh like was mentioned in previous

play18:25

talks remix has a great API so long

play18:29

story short Frameworks use whatever the

play18:32

Frameworks provide you and if you don't

play18:34

have that then use Query works well too

play18:36

but uh with remix you could Define a

play18:38

loader function and you just get your

play18:41

items and that's going to be available

play18:42

to your component immediately you don't

play18:45

have to do that use effect dance next JS

play18:47

has something similar with get server

play18:49

side props so you could just awake get

play18:51

items in that function and return it as

play18:54

props over here into your actual

play18:56

components and so react query I'm sure a

play19:00

lot of you are using react query it's an

play19:02

excellent Library it's not a state

play19:04

management Library it's not even the

play19:06

fetching Library it's a caching library

play19:08

that works really well with fetching

play19:10

data so um in in this case I'm actually

play19:14

doing prefetch so I'm prefetching this

play19:16

data I'm populating it in and then I'm

play19:19

reading it so instead of use effect in

play19:22

summary

play19:23

you should either use Query or use a

play19:26

hook like that or use a framework or use

play19:30

another hook that was actually recently

play19:32

it's not out yet it's it was recently

play19:35

announced its use

play19:36

just use

play19:38

so I I'm serious you might be thinking

play19:40

like

play19:41

what kind of hook name is this I mean

play19:43

it's a legitimate hook name but it is

play19:45

actually an RFC first class support for

play19:47

promises and async the weight and so

play19:49

this is actually probably maybe going to

play19:53

be the future of using suspense inside

play19:56

of react so basically you would fetch a

play19:58

post and

play20:00

um you would have some sort of caching

play20:01

mechanism which react is still trying to

play20:04

figure out but again this is how use

play20:05

Query Works under the hood as well and

play20:08

so this is going to automatically

play20:09

suspend your components so use it seems

play20:13

really cool terribly named

play20:15

um but you know that's the future

play20:19

all right and so Danny ibrahimov

play20:20

actually said there's a lot of problems

play20:22

with fetching and use effect you might

play20:24

have race conditions no instant back

play20:26

button so basically when you um go back

play20:29

to a page you have to load that data

play20:31

again

play20:32

um no initial HTML content when you

play20:35

render your page you're going to see a

play20:36

lot of nasty loading Spinners and also

play20:39

chasing waterfalls so if you're fetching

play20:40

inside of your parent component you have

play20:42

to wait for that and then when your

play20:44

child component renders after that's

play20:46

done touching you have to wait for that

play20:48

it gets really annoying

play20:50

um there's also the fact that you don't

play20:52

need to use effect for initializing

play20:55

Global Singletons so um for example we

play20:59

know that this is now going to run twice

play21:01

so instead of it uh running twice we

play21:05

could use a ref to track whether it was

play21:07

called or not but that gets really

play21:09

annoying

play21:10

um and so we could you know just move

play21:12

that ref outside of the component

play21:14

especially if you're running this effect

play21:16

inside of the root components uh but

play21:20

you're still using a use effect so

play21:22

instead honestly just call it outside of

play21:25

the component there's really no harm in

play21:27

it now you might be you know saying what

play21:29

about server side rendering what about

play21:31

testing just move it into a function the

play21:34

point of it is that you don't need to

play21:36

put everything inside of a component

play21:40

and so finally the one that I really

play21:42

want to get into you don't need to use

play21:45

use effects for handling user events so

play21:47

like we talked about before this is

play21:50

submitting logic when we submit a form

play21:52

uh it looks very similar to The Promise

play21:54

example except now we have extra

play21:56

variables for whether it's loading

play21:58

whether it's canceled we also have to

play22:00

keep track of Errors instead of this you

play22:03

could just put it inside of a side or a

play22:06

side effect inside of the event handler

play22:08

so this is on submit right over here and

play22:12

this you know it also gets pretty nasty

play22:15

so that's why I would say that when you

play22:17

are working on logic like this you

play22:20

should extract it out to a hook and so

play22:22

my favorite hooks are of this form where

play22:24

we get the states and we could also send

play22:27

in events some of you might know me

play22:29

because I created X date this is how

play22:32

xdate works this is how Redux works this

play22:34

is how use reducer works and it is a

play22:37

very very useful API because all of our

play22:40

actions and events that happen are

play22:43

reduced to a single line where you're

play22:45

just sending an event object so it makes

play22:47

things very clear and very easy and

play22:50

succinct and so I'll actually give you a

play22:52

really quick demo of this

play22:54

um including like just a you know a use

play22:57

effect demo so this is an example

play22:59

application and here's how it works when

play23:01

I click the video

play23:03

it opens and plays when I click outside

play23:05

of it it closes and when the video is

play23:09

finished right now it immediately closes

play23:12

so

play23:14

um right now

play23:15

um actually in the back can you all see

play23:17

these use effects over here can you read

play23:19

them

play23:19

I I can't read them either because

play23:22

there's too many of them and uh they're

play23:25

really really complicated so I I have a

play23:28

bunch of use effects here this one is

play23:30

controlling whether the video is playing

play23:31

or paused this one is controlling

play23:33

whether the video has ended and you know

play23:36

we have that nasty if statement in there

play23:38

uh and this one is controlling whether

play23:41

we have pressed the Escape key because I

play23:42

could press the Escape key and close it

play23:44

now I also want the user behavior of

play23:47

when the video ends I wanted to wait two

play23:50

seconds before closing and so that

play23:53

that's probably going to be another use

play23:54

effect we need to add code to you know

play23:57

all of the other three use effects just

play23:59

to make sure that we're handling those

play24:01

correctly and we're not closing it

play24:03

prematurely uh so instead I want to show

play24:06

you by ways of diagramming how I would

play24:10

model this instead so here

play24:14

uh right now we have the behavior where

play24:18

we start in the mini state where our

play24:20

video player is nice and small and on

play24:23

some toggle we transition to a full

play24:26

state

play24:27

so you know we just toggle back and

play24:29

forth

play24:30

we could toggle like this now in the

play24:33

full State this is what I mean by

play24:36

declarative effects so um in full when

play24:39

this is open I actually want to play the

play24:42

video so I'm just going to add this

play24:45

as an action

play24:47

like that let me zoom in and when I exit

play24:51

the full so when I go from Full to mini

play24:52

I want to pause the video because the

play24:56

video might not be done so I just want

play24:58

to make sure it's being paused so this

play25:00

it's sort of like a flowchart you could

play25:02

Envision how it works like we're mini

play25:04

and then when we click we're in the full

play25:06

mode where we see the video playing and

play25:08

when we toggle we're back to Mini

play25:11

now uh there's a couple of other things

play25:13

that we could do so um I'm going to add

play25:16

an invocation and so basically we're

play25:19

going to add some listeners this is

play25:21

going to uh listen for

play25:24

um whether the video ended or not

play25:26

and I also want to listen for

play25:30

um

play25:31

or actually before that I want to do

play25:33

this so we are going to also add events

play25:35

for video ended

play25:38

and we are going to add an event

play25:41

for

play25:43

he dot Escape

play25:45

all right so this is our logic so far so

play25:49

when we're in full mode whether the

play25:51

video ends or you press the Escape key

play25:53

or you click outside the video it should

play25:56

go back to mini and it should pause the

play25:58

video so you know that makes sense so

play26:00

far so um

play26:02

I I actually also want the additional

play26:05

behavior of when I'm in the full States

play26:08

um like let's just say that this is

play26:10

playing

play26:13

I also want to

play26:15

um wait for two seconds so how can we do

play26:19

this

play26:20

in like this diagram so I could just you

play26:23

know have a state for when it stopped

play26:25

and I could move this video dot ended

play26:28

I'm going to move this over here drag it

play26:30

a little

play26:32

and so when the video stops here's the

play26:34

logic and this is logic that you might

play26:36

be sharing with a designer or a project

play26:38

manager that when the video stops I want

play26:42

to wait for two seconds so

play26:45

oops let me reload that real quick all

play26:48

right so I want to wait

play26:50

huh weird uh I want to wait for two

play26:53

seconds so here's how we can do that

play26:56

pretend you didn't see that all right so

play26:59

after I'm gonna do

play27:01

two seconds I'm going to transition to

play27:04

mini so if you're trying to explain this

play27:06

logic to someone you could simulate it

play27:09

here and say we're going to toggle to

play27:11

full and then when you press either

play27:13

toggle or key Escape it goes back to

play27:16

mini but when the video ends then after

play27:20

two seconds we want it to close and go

play27:23

back to the mini state where the video

play27:25

is paused and it's you know where we're

play27:28

no longer seeing the full video

play27:30

so a couple of other things I have to

play27:32

add in order to listen to these events

play27:34

key escaping video ended I need to

play27:38

um add some invocations so

play27:40

video ended and also

play27:43

uh key Escape so basically we're

play27:46

listening for these two things to happen

play27:48

and

play27:50

this is our complete Logic for how I

play27:52

want this to work now I only have a

play27:55

minute and 44 seconds so let's see how

play27:58

quickly I could live code this thing in

play28:01

fact actually I probably don't have time

play28:03

to do that so I am just going to copy

play28:05

the code over here

play28:07

and right now this is not working no

play28:10

magic tricks okay not working

play28:12

so I'm gonna go here

play28:15

paste this machine in this is an X8

play28:18

machine and

play28:20

um

play28:21

oh I I forgot something

play28:23

actually it literally says David don't

play28:25

forget this so oops all right

play28:29

Don't Clap yet um

play28:31

all right so

play28:33

we so when I click the player I have to

play28:35

send the toggle event and that's all I

play28:37

have to do so

play28:39

hopefully this works if I click here if

play28:43

I click outside if I click here if I

play28:45

press escape and if I click here and I

play28:48

wait for the video to end

play28:50

give it two seconds one two close there

play28:53

we go

play28:54

[Applause]

play29:02

all right so this is now available at

play29:04

stately.ai studio and uh we actually

play29:07

released our v1.0 today so please check

play29:11

this out if you if you want to

play29:14

um but yeah I'm really excited that we

play29:16

have this out so um in short just to

play29:19

summarize because I have 20 seconds when

play29:21

do effects happen in these State

play29:23

transitions where an event is occurring

play29:26

and then you model that as an effect so

play29:28

where do these action effects go inside

play29:31

of these State transitions which most of

play29:34

the time happen to be executed at the

play29:36

same time as those event handlers so in

play29:39

short use effect is not for all effects

play29:41

it's for synchronization State

play29:43

transitions are what trigger effects

play29:45

action effects go in event handlers you

play29:48

should render as you Fetch and also it

play29:51

might be nice to model effects with

play29:53

steam machines so thank you very much

play29:55

react Brussels

Rate This

5.0 / 5 (0 votes)

Related Tags
React HooksState ManagementSide EffectsUseEffectSynchronizationWeb DevelopmentJavaScriptCode OptimizationReact 18Event Handling