Hello friends, let's talk about useReducer,
why and how we should use it. It's one of the most important React hooks,
and once you learn it, you'll be able to handle React states in a more professional way, and
also you'll understand the structure of Context API and state management tools like Redux. So if you have a Youtube playlist where you
save the important tutorials of React, this video is definitely the one you'll want to
add there. Okay. Let's begin with this question. What is useReducer? useReducer is a React hook, that allows you
to manage the states of components. Basically, it's an alternative to useState. They both create a new state and update it. But the difference is the way to update states. In useState, we use setState function to update
the state variable but in useReducer, it's a little bit more complicated compared to
useState, but actually, it makes your code much cleaner. I'm gonna show you how to use it, but before
let me answer the most popular question: When to use useState? When to use useReducer? The first use-case is when you update multiple
states in a single function. Let's say we have loading, post, and error
states. Basically, when we click on this button it's
gonna try to fetch a post from an API and update these states during that process. And here, when loading this button text will
be "wait", we'll write here the post title, and if there is an error, we'll show it here. Okay, let's do that. When we click, firstly the loading state will
be true, then if it's successful, we'll update the post and the process will be done so loading
will be false again. And if there is something wrong, the error
will be true and we'll end the process. As you can see, the post title is here, and
this text turned back to the initial text. And if there is an error, it's gonna be here. But when we click again it shouldn't be here
anymore. So I'll make it false at the beginning. As you can see, there is nothing wrong, it
works properly but here there are six setStates in just one function. So when two or more states change together
it's better to use useReducer hook. We are gonna replace this with useReducer
but before let's take a look at the second common use case. If you have a complex state like this, and
you need to update every single item inside it, you should definitely consider using useReducer. Because if your form elements are not of the
same type, it's gonna be harder to handle them in a component. We have a category here, and a text area where
we can add multiple tags, and we can remove them by clicking on a specific tag. And there is a quantity. I can increase or decrease this number. Writing all these functions here can be confusing
and also reduces the code readability. And remember the useState tutorial, we have
to use this updating function all the time, and you'll most probably make a mistake, especially
if you have nested objects or arrays. So we should replace it with useReducer also. Okay, let's see how to use useReducer for
the first example. So I'll remove all these states and set states
in the function. And I'll create a new file. postReducer.js. You can write it in the component directly,
but I recommend you to separate it like this. Firstly I'm gonna create an initial state
and it'll include loading, post, and error. Just like we did for useState but this time,
we have only one state. Remember, we are not updating multiple states
anymore. After that, we are ready to create the reducer
function. And it takes 2 arguments. The first one is the current state. In the beginning, it's gonna be this initial
state and we'll be able to update it. And the second one is "action" which I'll
explain soon. Basically, it's a function that can update
the state and return the new version of the state. For example, when we click on this button,
we'll say "hey reducer, I'm starting to fetch the post." We'll give only this information, nothing
else. And it's gonna take this information and make
the loading true, and error false. After fetching we'll say "Hey reducer, it's
successful, and here is the API response". It will take our message and make the loading
false again and update this post according to the API response that we send. And finally, if there is an error, we'll send
the information again, and it'll make the "error" true and "loading" false. So, we are gonna send all those information
using this action here. We'll have different action types. if the action type is FETCH_START for example,
it'll return loading:true, error:false, and there will be no post. if it's FETCH_SUCCESS, loading will be false
again, error, false and the post will be the API response, and we'll send it here using
action. We'll say the action type is FETCH_SUCCESS
and the action payload is this data. In this case, it'll take the action.payload,
and update the state. You can say here whatever you want. action.data, action.post whatever. But the payload is the most common usage. If you are confused by the way, just hold
on. During the second example, you are gonna understand
much better. In this example, we are just learning the
structure. Okay, and for FETCH_ERROR action type, we
are gonna update the error. But as you realize using else if structure
all the time and it's not a good idea. Because we can have maybe ten maybe more action
types. So in this situation using a switch case block
is a better solution. I'll say switch, action type. And if this action type equals FETCH START,
return this state. If it's FETCH_SUCCESS, return this state. And if it's FETCH_ERROR , error will be true,
loading will be false and we won't have any posts. As you can see there is a warning here because
if you are using a switch case block you have to provide a default case here. It means if the action type is not one of
them, just return something. And we'll return just the current state. And one more thing I want to mention here. You don't have to return every single property
like that. You can take all elements of the previous
state, and just update whatever changes. The error was false at the beginning and when
it's successful it'll be still false. So we don't have to write it, it'll stay the
same. Of course, in this example, it doesn't make
that much difference. But when you have more state properties it
will. Okay, let's export this reducer and this state
and use them in the component. To call this function we'll use the useReducer
hook. We'll pass this function and the initial state. Basically, the useReducer hook takes this
initial state and passes here. And it returns the current state, in this
case, we can use it instead of useState variables. And also it returns the dispatch function. And this function allows us to send actions
to the reducer. Let's do that. I'll say "dispatch", and action object. Remember what we are sending. The type will be FETCH_START and that's all. It's gonna see this action type and update
the state. What about this? I'll say dispatch. type FETCH_SUCCESS but remember one more thing
we need. And it's payload. I'll send this data, it'll take it and update
the post. Finally, FETCH_ERROR. Okay. Let's try. As you can see it work as we expected. Perfect. Let me give you one more tip. If you make any typo here, vsCode is not gonna
warn you. Because it's just a string. And believe me, it'll happen all the time. To prevent this problem you can create a new
file and export all these types. In this case, instead of a string, you can
use those variables. ACTION_TYPES dot and as you can see it shows
all object properties, so you can't make a mistake right now. I'll change all of them. Okay, perfect. Let's take care of this example also and you'll
understand everything better. I'll take this state and create a reducer
file. I'll say initial state and paste it and formReducer. Switch. And default. And let's see how many different actions we
are gonna need. These items just store strings or numbers
so we'll handle them in one action. Let's say CHANGE_INPUT. We are gonna write here some tags and separate
them with commas, So I'll take each tag and push inside this array. Let's say ADD_TAG. And when we click on those tags. They'll be removed. I'll say REMOVE_TAG. And we are gonna increase and decrease this
number. INCREASE, DECREASE. Okay. I'll export this reducer, and let's call it
here using the useReducer hook. Let's use this state. It's not the product useState object anymore,
it's state. Okay. In the useState tutorial, I've already explained
how to update multiple text inputs. So I'll pass here faster. I'll give a name for each input. And make sure that those names are exactly
the same names in the state. And onChange event. handleChange. Let's create this function. So whenever we change any input here, we'll
update the state. Type will be CHANGE_INPUT. So how we can update them? I'll spread the current state, so these elements
won't change. And I'll update inputs according to their
names. And update them using their values. So let's send them here. Let's check. Consol.log(). And perfect. I'll take care of this tags section but before
let's increase and decrease this number it's easier. All state elements will be the same but quantity,
the previous quantity + 1. In the same way, but this time -1. And that's all. Let's dispatch these actions. On click. dispatch. type decrease. and increase. Okay. And tags. We should dispatch this action when we click
on this button but how we can reach this text in this input? I'll not create a useState to store this text. Instead, I can use the useRef hook. Let's say tagRef, useRef hook. And I'm gonna write it here. In this case, I can reach the value of this
textArea anywhere in the component. It's great because we'll need it when we click
on this button. Let's write a click event. handleTags. I'll create this function here. Right now, I'll take this string, make it
an array, and separate all these elements using commas. It's really easy to do that. I'll just use Javascript split method. Separate them using comma. Then, I'll take this array. And for each individual tag, I'm gonna dispatch
the ADD_TAG action. And as a payload, I'll send the tag. In this case, it'll send 1, after that 2,
after that 3. Let's write state again and I'll update the
tags array. I'll say keep the previous array but add here
one more. And it'll be action.payload. And perfect. And when we click them, we are gonna dispatch
this action. Let's say onClick, dispatch, and REMOVE_TAG,
and the payload will be tag again. Basically, the reducer takes this tag, and
filters this array. Let's do that. tags. I'll filter the previous array. It's gonna take each tag and compare them
with action.payload. And it'll return all elements but this tag. And that's all. As you can see useReducer looks neat and clean. I hope you understood how to use it. Don't forget to practice it by yourself. You can find the source code in the description
below. Okay. As always, if you learned something new today,
please like the video, and let me know which React hook or project you want to see in the
next tutorial. You can support Lama dev, by joining to channel
or using the link in the description below. I hope I'll see you in the next tutorial. Goodbye.