Managing State With useReducer | Lecture 185 | React.JS 🔥

The Coding Classroom
2 Jan 202414:14

Summary

TLDRThe video script discusses the useReducer hook in React, which centralizes state updating logic in a reducer function, ideal for complex state management. It contrasts useReducer with useState, highlighting that useReducer allows for related state pieces to be managed together, resulting in cleaner, more readable components. The script explains that a reducer function takes the current state and an action to return the next state, emphasizing immutability and the lack of side effects. It also describes the dispatch function's role in triggering state updates based on actions. An analogy of withdrawing money from a bank illustrates the concept, clarifying the roles of dispatcher, reducer, action, and state in the useReducer mechanism.

Takeaways

  • 🧠 UseReducer Hook: Centralizes state updating logic in a reducer function.
  • 📦 Complex State Management: useReducer is ideal for managing complex state and related pieces of state.
  • 🔄 useState Limitations: In complex scenarios with multiple state variables and updates, useState can become overwhelming.
  • 🎯 Synchronous State Updates: useReducer allows for multiple state updates as a reaction to the same event.
  • ⚙️ Reducer Function: A pure function that takes current state and action to return the next state without mutation.
  • 🚫 Immutable State: React's state must not be mutated directly; reducers must return new state objects.
  • 📜 Action Object: Describes state updates with an action type and payload, which is input data.
  • 🔧 Dispatch Function: Triggers state updates by sending actions to the reducer from event handlers.
  • 🔄 State Update Cycle: Dispatching an action leads to state computation by the reducer and subsequent component re-render.
  • 💡 Reducer Analogy: Like the array reduce method, React reducers accumulate actions into a single state over time.
  • 📈 useState vs useReducer: useState is simpler but useReducer solves complex state management problems and keeps components clean.

Q & A

  • What is the primary purpose of the useReducer hook?

    -The useReducer hook is used to centralize state updating logic in a reducer function, making it an ideal solution for managing complex state and related pieces of state in a React application.

  • Why might using useState be insufficient for managing state in certain situations?

    -In situations where components have many state variables and updates spread across multiple event handlers, or when multiple state updates need to occur simultaneously, using useState can become overwhelming and difficult to manage.

  • How does useReducer help with the challenges of managing complex state?

    -useReducer allows for the decoupling of state logic from the component itself by moving all state updating logic into a single reducer function, resulting in cleaner and more readable components.

  • What does a reducer function typically take as inputs?

    -A reducer function typically takes the current state and an action as inputs, and based on these values, it returns the next state (the updated state).

  • What is the significance of immutability in the context of React state management?

    -In React, state is immutable, meaning the reducer function is not allowed to mutate the state directly. Instead, it must always return a new state object based on the current state and the received action.

  • What is the role of the dispatch function in useReducer?

    -The dispatch function, returned by useReducer, is used to trigger state updates by sending an action to the reducer, which then computes the next state based on the current state and the action.

  • How does the useReducer mechanism differ from useState in terms of updating state?

    -With useState, you directly call setState with the new state value to update the state, whereas with useReducer, you use the dispatch function to send an action to the reducer, which then determines how to update the state.

  • What is the analogy used in the script to help understand the useReducer mechanism?

    -The analogy used is that of withdrawing money from a bank. The customer (dispatcher) goes to the bank (reducer) to request money (state update), and the bank employee (reducer function) handles the withdrawal from the vault (state object) based on the customer's request (action).

  • What does the action object represent in the useReducer mechanism?

    -The action object represents a request to update the state. It usually contains an action type and a payload, which provides the necessary information for the reducer to determine how to update the state.

  • How does the useReducer hook manage related pieces of state?

    -useReducer manages related pieces of state by storing them in a state object that is returned from the hook. This allows for a more organized and efficient way of handling complex state updates.

  • What is the benefit of using useReducer over useState in complex scenarios?

    -useReducer provides a more structured and scalable approach to state management, especially for complex scenarios with multiple related state variables and updates. It helps maintain a clear separation of concerns, making the codebase easier to understand and maintain.

Outlines

00:00

📚 Introduction to useReducer and its Benefits

This paragraph introduces the useReducer hook as a centralized solution for managing state updates, particularly for complex scenarios where multiple state variables and updates are involved. It contrasts useReducer with the useState hook, highlighting the challenges of using useState for managing state in larger, more complex components. The useReducer hook is presented as an alternative that allows for related state pieces to be managed together, promoting cleaner and more readable component code by moving state logic into a reducer function. The paragraph emphasizes the importance of the reducer function in updating the state object and the concept of immutability in React, where the reducer must return a new state object without mutating the existing one.

05:02

🔄 How useReducer Works: Actions, Dispatch, and Reducers

This paragraph delves into the mechanics of useReducer, explaining the roles of action objects, the dispatch function, reducers, and the state object. It describes how actions contain information for the reducer, typically in the form of an action type and a payload. The reducer's function is to take the current state and an action to compute the next state, which then triggers a re-render of the component. The analogy of a bank transaction is used to illustrate the process, where the customer (dispatcher) requests an action (withdrawal), and the bank employee (reducer) performs the update on behalf of the customer, keeping the process organized and abstracted from the user.

10:03

🏦 Analogy of useReducer with Bank Transactions

The paragraph uses a detailed analogy of banking to clarify the useReducer mechanism. It compares the state to a bank's vault, where data is stored and updated. The customer represents the dispatcher, who initiates the state update by requesting an action. The bank employee is likened to the reducer, responsible for executing the action based on the instructions (action object) provided by the customer. This analogy emphasizes the separation of concerns, where the reducer handles all the logic for updating the state, allowing developers to maintain clean and straightforward components. The analogy also highlights the importance of the action object, which contains the necessary information for the reducer to perform its task.

Mindmap

Keywords

💡useReducer

The useReducer hook is a React feature that allows for the management of complex state by centralizing all state updating logic in a single reducer function. It is an alternative to useState and is particularly useful when dealing with multiple state variables and complex updates that may involve dependencies or simultaneous changes. In the video, useReducer is introduced as a solution to the challenges of managing state in large components or across multiple components.

💡useState

The useState hook is a fundamental React feature that enables components to have and manage their own state. It provides a way to add state to function components by returning an array with two elements: the current state and a function to update it. However, when state logic becomes complex, involving many variables and updates, useState can become insufficient, leading to the need for useReducer.

💡reducer function

A reducer function is a pure function that takes in the current state and an action, and returns the next state based on these inputs. It is the core of the useReducer hook, responsible for all state updates. The reducer function must not mutate the state directly but instead should return a new state object, ensuring that the state changes are predictable and easy to trace.

💡immutable state

In React, state is considered immutable, which means it cannot be changed directly. Instead, updates to the state must be made by creating a new copy of the state with the desired changes. This ensures that the state changes are predictable and helps React to optimize rendering. The reducer function must adhere to this principle by always returning a new state object without mutating the existing one.

💡action

An action in the context of React's state management is an object that describes how the state should be updated. It typically contains an action type, which indicates the kind of change to be made, and a payload, which is the data associated with the action. Actions are dispatched to the reducer, which uses them to determine the new state.

💡dispatch function

The dispatch function is returned by the useReducer hook and is used to trigger state updates by sending actions to the reducer. It acts as a bridge between the component's event handlers and the reducer, allowing developers to dispatch actions in response to user interactions or other events.

💡state object

A state object is a data structure, usually an object, that holds the state managed by the useReducer hook. It contains related pieces of state, and the reducer function is responsible for updating this object in response to dispatched actions. The state object encapsulates the application's state, making it easier to manage and reason about within complex components.

💡component

In React, a component is a piece of code that returns a UI representation of data. Components can be simple or complex, managing their own state and props to render the appropriate content. The video script discusses how managing state can become challenging as components grow in complexity, with many state variables and updates spread across multiple event handlers.

💡event handler

An event handler in React is a function that is executed in response to an event, such as a user interaction like clicking a button or typing in a text field. Event handlers are often used to update the component's state. The script discusses the complexity that arises when multiple state updates need to happen in response to a single event, which can be managed more effectively with useReducer.

💡pure function

A pure function is a function that has no side effects and always produces the same output given the same input. In the context of React's reducer functions, purity ensures that the function does not mutate the state or cause any external changes but only returns a new state based on the current state and the dispatched action.

💡re-render

In React, a re-render is the process of re-executing the render function of a component to update the UI with the latest state or props. When the state is updated, React re-renders the component to reflect these changes on the screen. The script explains that updating state with useReducer, just like with useState, will trigger a re-render of the component instance.

Highlights

The useReducer hook centralizes state updating logic in a reducer function.

useReducer is an alternative to useState for managing complex state and related state pieces.

As components and state updates become complex, useState may not be sufficient.

Multiple state updates often need to happen simultaneously as a reaction to the same event.

Updating one piece of state can depend on one or more other pieces of state, which can be challenging with many states.

useReducer returns a state and a dispatch function, which helps in managing state more effectively.

The reducer function is responsible for all state updates, moving the logic from event handlers into a central place.

Decoupling state logic from the component makes the components cleaner and more readable.

Reducers must be pure functions that always return a new state based on the current state and received action.

Actions are objects that describe how state should be updated, typically containing an action type and payload.

Dispatch function triggers state updates by sending actions to the reducer.

Updating state with useReducer triggers a re-render of the component instance.

The reducer function accumulates all actions into one single state over time, similar to the array reduce method.

Dispatch function coordinates the state update process and gives the reducer access to the current state.

useReducer is more complex to set up than useState but solves specific problems in managing state.

An analogy of withdrawing money from a bank helps clarify the useReducer mechanism.

The state is like a bank's vault where data is stored and updated.

The customer represents the dispatcher, requesting the state update through an action.

The bank employee is the reducer, performing the update based on the action's instructions.

The action is the request message containing the action type and payload for the withdrawal.

Transcripts

play00:01

‫So we just learned how to use the useReducer hook

play00:04

‫to centralize all the state updating logic

play00:07

‫in one central place, which is the reducer function.

play00:12

‫So let's now dive deeper into the concept of reducers

play00:16

‫and how and why they can make our applications

play00:19

‫a lot better in certain situations.

play00:24

‫So up until this point,

play00:25

‫we have been using the useState hook

play00:28

‫to manage all our state, right?

play00:31

‫However, as components and state updates

play00:34

‫become more complex, using useState to manage all state

play00:39

‫is, in certain situations, not enough.

play00:42

‫For example, some components have a lot of state variables

play00:46

‫and also a lot of state updates

play00:49

‫that are spread across multiple event handlers

play00:52

‫all over the component or maybe even multiple components.

play00:57

‫And so this can quickly become overwhelming

play01:00

‫and hard to manage.

play01:01

‫It's also very common that multiple state updates

play01:04

‫need to happen at the same time

play01:07

‫so as a reaction to the same event.

play01:10

‫For example, when we want to start a game,

play01:13

‫we might have to set the score to zero,

play01:15

‫set an is playing status and start a timer.

play01:20

‫And finally, many times updating one piece of state

play01:24

‫depends on one or more other pieces of state,

play01:28

‫which can also become challenging

play01:30

‫when there is a lot of state.

play01:33

‫And so in all these cases, useReducer can really help.

play01:38

‫So these are the problems that reducers try to solve

play01:41

‫and so let's now see how.

play01:45

‫So first of all, useReducer is an alternative way

play01:49

‫of setting and managing state,

play01:51

‫which is ideal for complex state

play01:54

‫and for related pieces of state.

play01:58

‫Now, we already used useReducer in the last two lectures

play02:02

‫and this is what that looked like.

play02:05

‫So we call useReducer

play02:06

‫with a reducer function and its initial state

play02:10

‫and it returns a state and a dispatch function.

play02:14

‫So starting from the beginning, when we use useReducer,

play02:19

‫we usually store related pieces of state

play02:21

‫in a state object that is returned from the useReducer hook.

play02:27

‫Now, it could also be a primitive value

play02:29

‫but usually, we use objects.

play02:32

‫Now, as we already know, useReducer needs something called

play02:36

‫a reducer function in order to work.

play02:40

‫So this function is where we place all the logic

play02:43

‫that will be responsible for updating the state

play02:47

‫and moving all state updating logic from event handlers

play02:51

‫into this one central place allows us

play02:54

‫to completely decouple state logic from the component itself

play02:58

‫which makes our components so much cleaner

play03:02

‫and so much more readable.

play03:04

‫So when we manage state with useReducer,

play03:08

‫it's ultimately this reducer function

play03:10

‫that will be updating the state object.

play03:14

‫So in a way.

play03:15

‫it's a bit like the setState function in useState

play03:18

‫but with superpowers.

play03:21

‫Now in practice, the reducer is simply a function

play03:24

‫that takes in the current state and an action,

play03:28

‫and based on those values, returns the next state,

play03:32

‫so the updated state.

play03:34

‫Now, keep in mind that state is immutable in React.

play03:39

‫This means that the reducer

play03:41

‫is not allowed to mutate the state,

play03:44

‫and in fact, no side effects are allowed

play03:47

‫in the reducer at all.

play03:49

‫So a reducer must be a pure function

play03:52

‫that always returns a new state.

play03:56

‫And again, based on the current state

play03:58

‫and the received action.

play04:01

‫And speaking of the action, the action is simply an object

play04:05

‫that describes how state should be updated.

play04:09

‫It usually contains an action type and a so-called payload

play04:14

‫which is basically input data.

play04:16

‫And it's based on this action type and payload

play04:20

‫that the reducer will then determine

play04:22

‫how exactly to create the next state.

play04:26

‫And now the final piece of the puzzle is this.

play04:30

‫How do we actually trigger a state update?

play04:33

‫Well, that's where the dispatch function comes into play.

play04:38

‫So useReducer will return a so-called dispatch function

play04:43

‫which is a function that we can use

play04:45

‫to trigger state updates.

play04:48

‫So instead of using setState to update state,

play04:52

‫we now use the dispatch function in order to send an action

play04:56

‫from the event handler

play04:57

‫where we're calling dispatch to the reducer.

play05:01

‫And as we already know,

play05:03

‫the reducer will then use this action

play05:05

‫to compute the next state.

play05:08

‫Okay, so these are all the pieces that need to fit together

play05:13

‫in order to effectively use the useReducer hook.

play05:17

‫So an action object, a dispatch function, a reducer,

play05:21

‫and a state object.

play05:23

‫But now let's also look at the diagram

play05:26

‫to really see how all of these pieces actually fit together

play05:30

‫in order to update state.

play05:33

‫So let's say

play05:34

‫that we're in an event handler in some component

play05:38

‫and we now need to update some state.

play05:42

‫So what do we do? Well, that's right.

play05:45

‫We call the dispatch function

play05:47

‫that we got back from useReducer

play05:50

‫in order to dispatch an action to the reducer.

play05:54

‫And this action, as we learned before,

play05:57

‫is an object that contains information for the reducer.

play06:01

‫So information about how the reducer

play06:04

‫should update the state.

play06:06

‫In this case, the action type is updateDay

play06:10

‫and the payload is 23, which probably means that the reducer

play06:14

‫will set the day state to 23.

play06:17

‫Now, the object doesn't need to have this exact shape

play06:21

‫with a type in the payload, but it's a standard

play06:24

‫that has been adopted by most developers.

play06:28

‫Now basically, the reducer takes in this action

play06:32

‫together with the current state

play06:34

‫and it will then return a brand new state object

play06:38

‫which we usually call the next state

play06:41

‫in the context of reducers.

play06:43

‫And as always with state,

play06:45

‫updating state will then trigger a re-render

play06:48

‫of the component instance.

play06:51

‫Now, if you're wondering why the reducer function

play06:54

‫is actually called a reducer,

play06:56

‫the answer is that it's because it follows

play06:59

‫the exact same idea as the array reduce method.

play07:04

‫So just like the reduce method

play07:06

‫accumulates all array values into one single value,

play07:10

‫the React reducer accumulates all actions

play07:14

‫into one single state over time.

play07:18

‫Okay now, behind the scenes,

play07:20

‫the dispatch function has access to the reducer

play07:24

‫because we passed it into the useReducer hook, right?

play07:29

‫So dispatch is really coordinating this whole thing

play07:33

‫and also giving the reducer access to the current state.

play07:37

‫And now to understand this even better,

play07:40

‫let's compare the mechanism of useReducer

play07:43

‫with a much simpler useState mechanism.

play07:47

‫So when we use useState, we get back a setter function

play07:52

‫and let's just call it setState.

play07:55

‫And then when we want to update state,

play07:57

‫we just passed the new updated state value that we want

play08:02

‫and React will simply update the state

play08:05

‫which in turn will trigger the re-render.

play08:08

‫So it's a lot simpler and more straightforward

play08:12

‫than useReducer, but since useReducer solves the problems

play08:17

‫that we saw earlier in this lecture,

play08:19

‫it's a great choice in many situations,

play08:22

‫even though it's a bit more complicated to set up.

play08:26

‫But we will talk more about the big advantages of useReducer

play08:30

‫and also when to use it later in the section.

play08:35

‫Now, I understand that this whole idea

play08:38

‫of dispatching actions and writing reducers

play08:41

‫is super confusing in the beginning.

play08:44

‫I know because I do remember

play08:47

‫how confused I was back in the day.

play08:50

‫And so let me show you now a really helpful analogy

play08:54

‫that made all this really clear to me

play08:56

‫when I first learned about this.

play09:00

‫So imagine that you needed to take $5,000

play09:04

‫out of your bank account for some reason.

play09:07

‫Now, since this is a large amount,

play09:10

‫you can't just do it from an ATM,

play09:12

‫so you need to go physically to a bank.

play09:17

‫Now, once you are at the bank,

play09:19

‫how do you actually get those $5,000?

play09:22

‫Do you walk straight into the bank's vault,

play09:25

‫grab the cash, and then go home?

play09:28

‫Well, I don't think so, right?

play09:31

‫That's usually not how it works.

play09:34

‫How it does work is that you go into the bank

play09:37

‫and there you'll find a person sitting at a desk

play09:41

‫ready to assist you.

play09:44

‫Now, when you arrive at the bank,

play09:46

‫you already know how much cash you want to withdraw

play09:49

‫and from what account number.

play09:51

‫And so you walk right to the person

play09:54

‫and tell them that you would like to withdraw $5,000

play09:58

‫from account 923577 for example.

play10:02

‫What happens then is that usually the person

play10:05

‫will type something into his computer,

play10:08

‫check if you actually have the cash in your account,

play10:11

‫and if so, he goes to the bank's vault,

play10:14

‫and gets the money to finally hand it over to you.

play10:19

‫It's your money after all, right?

play10:22

‫But note the big difference between this real version

play10:26

‫and the previous version of the story

play10:29

‫where you just grabbed the cash yourself.

play10:32

‫In this real version, you told the person what to do

play10:35

‫and how to do it and he then got the money

play10:38

‫for you on your behalf,

play10:41

‫and so you didn't take the money directly yourself.

play10:44

‫And that's a huge difference.

play10:47

‫So does this maybe start to sound familiar?

play10:51

‫Well, I hope it does.

play10:52

‫And so let's now bring this analogy back to useReducer

play10:56

‫and identify what each of these pieces represents

play11:00

‫in the useReducer mechanism.

play11:03

‫And let's start with the most important thing, the state.

play11:07

‫So what do you think the state is in this analogy?

play11:11

‫Well, the state is represented by the bank's vault

play11:15

‫because this is where the relevant data, so the money,

play11:19

‫is stored and also updated.

play11:22

‫So the vault is what needs to be updated,

play11:25

‫and so that's our state.

play11:28

‫Nice, so with that out of the way,

play11:31

‫let's think about how the money is taken from the vault.

play11:35

‫So about how state is actually updated.

play11:39

‫So starting from the beginning,

play11:41

‫what do you think the customer going to the bank

play11:44

‫represents in this analogy?

play11:47

‫Well, the customer going to the bank

play11:49

‫and requesting the money is clearly the dispatcher

play11:53

‫because it is who is requesting the state update, right?

play11:58

‫And they're doing so by going to the person

play12:01

‫and requesting to withdraw the $5,000.

play12:05

‫So what is the reducer here and what is the action?

play12:10

‫Well, the reducer is going to be

play12:12

‫the person working at the bank

play12:14

‫because that's the one who actually makes the update.

play12:18

‫In this case, it's the one who goes to the vault

play12:21

‫to get your money.

play12:23

‫But how does the person know how much money to take

play12:27

‫and from what account?

play12:29

‫They know because you told him so

play12:31

‫exactly in your request message.

play12:34

‫And so that request message is clearly the action.

play12:38

‫In this example, the action can be modeled like this.

play12:42

‫With the action type being withdraw

play12:45

‫and the payload being the data about the withdrawal

play12:48

‫that you want to make.

play12:50

‫So summarizing, you went into the bank

play12:53

‫with a clear action in mind,

play12:56

‫you then dispatched that action to the reducer,

play12:59

‫so to the person working there who took the action,

play13:03

‫and followed the instructions

play13:05

‫to take the right amount of money from your account.

play13:08

‫So from state.

play13:10

‫he then gave you your money finishing this cycle.

play13:14

‫So you did not go directly into the vault

play13:17

‫and took your money.

play13:19

‫Instead, you had the person, as a middleman,

play13:22

‫who knows a lot better than you

play13:25

‫how to perform different actions on the vault.

play13:28

‫So he knows how to deposit, how to withdraw,

play13:31

‫how to open and close an account,

play13:34

‫how to request a loan, and more.

play13:37

‫And he does all this

play13:38

‫without you having to worry about the details.

play13:42

‫So exactly like a reducer function,

play13:45

‫which also decouples and abstracts

play13:48

‫all the state updating logic away from you, so that you

play13:51

‫can have clean and easy to understand components.

play13:56

‫Okay, so I hope that this now made the relationship

play13:59

‫between dispatcher, reducer, action, and state crystal clear

play14:05

‫and you will get plenty of opportunities

play14:07

‫throughout this section to practice all this.

Rate This

5.0 / 5 (0 votes)

Related Tags
ReactHooksStateManagementuseReducerReducerFunctionCodeSimplificationImmutabilityEventHandlingComponentDesignProgrammingConceptsWebDevelopment