Instructor: In the last section
we had a long demo of Redux.
We're going to continue in this section
by trying to answer that one burning question
that might be in your head, which is,
Why in the world would we ever write code like this?
What's the point?
Why do we have actions and reducers and stuff?
Why don't I just split this string and be done with it?
Hey, that's a fantastic question and that's probably
the most important question there is with Redux.
All these actions, reducers, store stuff.
What is the point of it?
Let me tell you what the point is in one sentence,
and I'm gonna try the rest of this course
to convince you of this one point.
Redux is one of the best libraries
in existence for scaling an application to be very large
with the least amount of code complexity.
In other words, as your apps start to grow,
start to get more features, Redux will help you write code
in such a fashion that your code doesn't also
have to grow in complexity.
So that's the point of Redux, but why is that the case?
You know, how can I make that claim?
Easy, I can easily make that claim.
The answer is the action system.
This whole process of dispatching an action
and receiving it inside the reducer.
With Redux actions give us the ability to
make predictable changes to the state of our application.
We will never, ever reach directly into our store,
you know reach directly into this thing,
and start messing around with a state
that is contained within it.
Instead, we will create an action
and actions modify our state in one very particular way.
That means that we can only modify our application state
in a very finite number of ways.
Now at this point in the app, I can only change my app,
my state, you know my state object,
which I retrieve via store.getState, in exactly one fashion
via the action that we wrote right here,
the action with type split_string.
Because I only have one action, I know without a fact
with absolute guaranteed certainty
that my application will always have a state
of either empty array
or...
I think I lost a getState on here.
Let me throw it back in really quick.
My state is always gonna be either an empty array
or an array with some strings inside of it.
That's it.
My state will never be an object, a string, a number,
a boolean, nothing else.
I will only ever have an array or an array of characters.
That's it.
Now that's my case for using Redux.
But for right now we should be a lot more concerned
with exactly how it works.
So let's review the code that we've got so far.
First we created a reducer.
(sighs) Lost my spot, there we go.
First we created a reducer.
A reducer is a function that produces some amount
of state, remember?
Then, we created a store and passed it that one reducer.
So we now have an instance of a store
that contains one reducer
and the state that that one reducer produces.
So by default, if we call getState on that store
we got back an empty array
because that is what the reducer produced.
Next, we made an action.
The action is a very specific directive
to tell the reducer how to updated its state
in a very particular fashion.
So our action was of type 'split_string'.
The type right here you can think of
as being like the command or the direction
that we're issuing to the reducer.
And then we also passed along a payload property.
The payload property is the data that we want
to communicate to the reducer.
So we can read this action in plain text, more or less as,
Hey reducer, please split the string,
and here is the string that I want you to split.
Next, we sent that string off or that, excuse me,
that action off to all of our reducers
by calling store.dispatch with the action.
When we dispatch an action, as we refer to it,
the action will get automatically sent
to all of the different reducers inside our application.
So let's experiment now by adding another action.
I want to make an action that will take my current array
of characters, which is "a","s","d","f",
and I want to just add another character
at the end of this array.
So I just wanna have an action that modifies my state
by adding another character to the end of the array.
So first we'll define an action.
So I'll write out my new action.
And I'm gonna call it very simply action2.
Remember that actions are objects.
They must have a type property.
I'm gonna give this one a type property of 'add_character'.
And then a payload of 'a'.
So if I read this like you know,
read this in a very literal fashion,
I would read this action2 as meaning,
Please add another character to the end of my state array.
And that character to add should be 'a'.
Okay, so that's that's basically the idea here.
So now we're going to dispatch this action.
Remember that by just creating an action, nothing, you know
nothing actually occurs by just creating one.
We have to actually dispatch it.
Dispatching an action sends it off to our reducer.
The reducer will rerun and whatever this reducer returns
becomes our state inside of our store.
We can then retrieve that state by calling store.getState.
So now we're going to dispatch the action
by calling store
dispatch
action2.
Again, when we pass an action to the dispatch method
it gets sent to all the reducers that are hooked
up to our store.
In our case, we've only got one right here.
Our reducer will then immediately rerun.
So this reruns right here.
And return a new update updated piece of state
for the store.
Notice though that even though
we added in another dispatch...
Let's check our state really quick.
If I call it store.getState
my state inside of my store has not actually changed.
So nothing has occurred yet.
I still just have a state of "a","s","d","f".
That's all there is right now.
So notice or our reducer has decided
that it does not care about the action that was dispatched.
So it just ignored it entirely.
This is a really important fact.
It means that if we have multiple reducers
in our application each reducer will be called
with every dispatched action.
So it's up to us to make sure
that this reducer right here watches
for actions of a very particular type.
So in our case, we want to make sure
that this reducer also responds
to an action of type "add_character".
So to do so, we'll add another if statement in here
or another catch.
Let's say, else if
action.type
equals 'add_character'.
Then I want to add that character
to the end of my array of characters right here.
Okay, so like this "a","s","d","f".
That means that I need to already know
what this reducer returned the last time it ran, right?
I need to know,
Okay, I already dispatched one action
and my current state is "a","s","d","f"
and now I intend to add on a character
to the end of that array,
a character 'a'.
So how do we get access to that previous array?
How do we get access
to like that previously calculated piece of state?
That is the job of the first argument to the reducer
which we have labeled as state here.
Reducers rerun many times throughout our application
and each time they are called, they are passed the result
of the last time they were called as the first element,
which we by convention refer to as state.
So again, each time we dispatch an action
we are making an incremental change
to the state of our application.
So now inside of here we'll take our state and we'll push
on 'action.payload' and then return that modified state.
Now our getState call returns "a","s","d","f" and "a".
So "a" is the new character that was appended at the end.
Let me pause for a moment though.
And I want to say that I just made a huge huge error
in the code that I just added right here.
Something that is very subtle.
I want you to take a look
at the two lines that I just added.
I took my current state object
and then I added in another character to it using push
and then I returned that object.
Now sure, this seems like an okay thing to do, right?
Like, Steven, you said we need to add in a character
to the end here.
Not, not quite.
So this is the one big rule of reducers.
Whenever we change our state object and reducers,
like whenever we, you know, make a tiny very subtle change,
we must return a completely new object
or a completely new array
or whatever data structure we might be using.
In other words, we do not mutate our data
as we did right here.
Instead we create a completely new data structure.
The code that I wrote right here
mutates our existing state array by calling push on it.
So I'm taking this existing array and I'm modifying it
which is not what we want to do.
We are going to, in a future section we're gonna talk
in great detail about why that's the case.
For right now, I just want to kind of plant it
in your head like this, kinda like seed
of a thought that we do not mutate our state in a reducer.
Instead we completely recreate recreate it.
So to fix this, I'm going to replace our these two lines
with a little bit of ES6 code.
I'm gonna instead write return
and then I'll open up an array
...state
comma
action.payload
and then close off the array like so.
This line right here now says,
Make a new array indicated by these outside brackets.
Take all of the elements in the current state array
and toss them in here and then also toss
in action.payload as the last entry as well.
More importantly, it creates an entirely new array
which is the requirement that we must satisfy
with Redux inside a reducer.
Now again, we'll talk about why this is the case
in the future, but for now, just remember the golden rule,
We always return brand new objects from reducers.
Okay? So believe it or not
I'm sure you're still incredibly confused,
but this is the end of our very brief introduction to Redux.
So I absolutely in no way, shape or form expect you
to be a master of Redux at all.
Not not one bit.
And in fact I'm going to continue in the next section
by assuming that you know absolutely nothing about it.
Redux is tough, it's hard, it's a different way of thinking.
So we're going to take things nice and slow.
The only intent I had inside of this section
and the previous sections was to introduce you
to the ideas of a reducer,
an action,
dispatching actions,
and pulling state out of our store.
Okay, so that's, those are the big like takeaways here.
That's all I really wanted you to get out of this.
We're gonna continue now in the next section.
And again, I'm basically going to assume
that you know nothing about Redux anyways.
So let's continue on the next application
and continue working on our actual React Native application.
I'll see you there.