Check out a free preview of the full Advanced Redux with Redux Toolkit course

The "Create Action" Lesson is part of the full, Advanced Redux with Redux Toolkit course featured in this preview video. Here's what you'd learn in this lesson:

Steve uses the createAction helper method to combine the declaration of an action type and an action creator. The action creator can be called with or without arguments or with a payload attached to the action.


Transcript from the "Create Action" Lesson

>> So, that's great for something that does not kind of take any argument. And sometimes that's true, right? They hit the logout button, a lot of times there's not extra information that you need to give it's like user is login out or like this thing was clicked, I need to do a thing.

But sometimes, if we're adding a task, sometimes it's helpful. Tell me more. [LAUGH] What task did they add? What action did they take with the counter or what have you, right? Depending on what you're working on. And so, yeah, we have payloads a lot of times and Redux itself doesn't really care.

It's like as long as you got action type. Wild West for anything else in that object. Use, reduce, and react literally doesn't care. It could be a number, it could be undefined for all it cares. But there is a pattern, it was originally called Flux standard actions. And the kind of there's a meta property and some other things.

But the two major pieces is the structure of the action in a way that has a type, which is the same string that we know and love. Like what happened? And I'll payload and making sure that instead of having a bunch of keys spread throughout this object and letting everyone your team guess where you put everything.

Just having a payload as a standard place to make sure you don't have collisions or anything like that this is kind of where all the different pieces go. You are for those keys and I bet you wanna just tell the pillar to be a number depending on what you want, all of those things are totally cool.

It is up to you but that is the convection that has been worldly popularized at this point and so that is what the truly would give you out of the box. What is really great about this is that in the very beginning for some of those types there's not a lot that you need to do.

So, for instance if you say add task is gonna take an action and we'll talk about like why went about do is gonna be slightly problematic and the second, but we'll go for it, we'll start with just action first, I'll show you what happens there. And so, in this case, we'll say our state which is we say, state, you'll notice that it is fully typed it knows the initial state, it's all set up and ready to go.

And if I try to push on the action.payload, this case it will work cuz I believe that counts as any. Now, I talked a lot about TypeScript before, one any in a code base is infectious. And so, this is not an array that can be anything we clearly said it should only be tasks, but as soon as you say that something is any TypeScript, I don't know what to do with you, I give up.

Luckily, adding a type to this is relatively straightforward. If you look at this, this is just a JavaScript function. Nothing special here, right? And we get kind of like a type system kind of supported in here. So, there are a bunch of different ones, there's action but then we want the one that action that has a payload, that's payload action.

And then all you have to do is say what type it should be getting. Alex, what's up?
>> Yeah, just a couple of quick questions. So, here I'm seeing you create the slice, and you create a bunch of reducers. And I remember in vanilla React Redux, every action and is dispatched to every reducer.

>> Yeah.
>> How does it act here? Does only the reducers from this list gonna receive those actions or no?
>> So, everything you know about Redux is still true, right? And that is a really great question, we will also cover later. I'll give you a, we'll do the sneak peek now, right?

So, Alex's question was hey, don't every action go to every reducer cuz combined reducers just taking a bunch of functions and running it there, it's just wiring up for you. These by default are bound to the slice, there is a another property here called extra reducers, right, which are one of the things that this slice is not in charge of that it might need to deal with.

So, at one point later today we're gonna do the feature, which is if like we remove a user from a list, unassign all their tasks, right? What I don't wanna have to do to your point is dispatch two actions, one to the user's slice, one to the tasks slice.

I just wanna say, yo, user was removed, unassign their stuff. All right, and like make it happen. So, there's actually a really great syntax and the nice part about this is even with that, even when it's like everything listens to everything, we will get full TypeScript support, right?

And we will get the full type safety with other than right now writing the type for the state, which I just use cuz I didn't want to write it in line, we've written very little TypeScript for full type safety, right? And I guess this typing this action right here, say like, this will be a task.

And what's nice about this is now I get all the safety that can autocomplete it and stuff along those lines. And now kind of if we look at this action, it assumes that that payload is a task. It will not let me accidentally call methods so on and so forth, right?

A lot of the error proneness of using redox is, it's a bunch of conditionals or switch statement, and you mistyped the action type, right? Or you call the wrong property on the object cuz you forgot the actual shape of it. So, stopping a lot of the mistakes and not really asking for much for you in return, right?

You get most of this for free at this point. And you can just kind of use it is really pretty great. So again, if we say, tasksSlice and we look at it now, it's action creator with a payload task and we'll dispense that action. So, even when we tried to call it, it will, like expect that the payload is a task, and make sure that we are handing it valid data, when we use it wherever our UI, whether that's react or something else as well, all of that will be there.

And so vast if you aren't a JavaScript code base, you will not get the enforcement but you will get the helpful, hover over answers to everything along the way. And so, the benefits are still there for something that you can very easily use today in your initial, in your existing infrastructure.

And so, instead of, just because I don't wanna scroll down, I'm just gonna say unshift. Unshift puts it at the beginning of the array versus the end. So that when I hit the button and I go, it doesn't work, it does work, I just have to scroll or put it at the top.

So we'll have that in place, it'd be great. And we'll kind of move to our first kind of little challenge here. Which is, what does this look like if I wanna migrate? Let's say like, this is cool, I like the fact that it wires up all of this for me, what are the pieces that make this up that I could use in my existing code base, right?

So, I have that little counter app for you to play around with and I will kind of show you a little bit and to give you kind of just an excuse to try it out in an app, but I will kind of show you some of the general pattern first, before I cut you loose on that.

So, I'm just gonna make a scratch file that I'm not gonna keep real quick. Yes?
>> Would you talk real quick about why it's called a slice?
>> I would love to. Naming things is hard, it's like a slice of your application. I guess the answer is no, I can't talk about why it's called a slice.

I personally, If I'm being candid and honest, it's not my favorite name for a thing.
>> Well, I guess they were talking about children.
>> Yeah.
>> [INAUDIBLE] better call.
>> Yeah, there's a bunch of names, yeah, the joke that bears repeating is the two hard problems computer science are naming things, cache invalidation off by one errors, right, naming things is hard.

Yeah, I remember it's one of those things where it's the first time I heard that I was like, I'm not taking that seriously. And now it's been four years and I don't think about it anymore. So, I agree with you, I feel that same initial thought.
>> I've always thought about it as like a slice of the pie.

>> Yeah.
>> I but I'm from Jersey, so I think about everything in terms of pizza.
>> Sure.
>> Yeah, awesome. So, imagine if you will, we had a simple reducer look like this. This is regular old redox this is like hi, I'm learning on React, I guess I have some type information in here.

But other than that, it is kind of just a regular, this could be useReducer for React. This could be anything, it doesn't matter, right? This is just the general pattern. It's technically not even Redux because it's just a reducer function and this idea of an action type. And you're like, I would like to to migrate from this, right?

The slice thing seems cool, but it's like automatically naming actions, I can't do any of this. All of the pieces are available to you as well. So, let's kind of talk about what this would look like if we wanted to migrate it and get a sense, that will help us understand a little bit, what's kind of going under the hood here?

And so, there are some, slices are made up from two component pieces that are just regular redux ideas. One is this createAction, right and createAction, there have been libraries that you could use that have done the similar thing that I think are great and a createAction is just trying to give you a standard way of making an action creator.

Action creator is a function that formats the action that you had to dispatch, right? And normally, it was one of those best practices that we were just supposed to know how to do. Nothing forces you to do it, nothing made you do it, but we're supposed to do it and we're all supposed to hope that everyone on the team did it consistently and in the same way.

And there's a lot of smiling and nodding going on right now because we all know that that's not how that works, right? Especially as the team grows, it becomes harder. So, with createAction, we can just say, what is the type of this action? So, for instance, if I needed actions, I could say increment.

Same way I did before. And then I give it some function. And let's say in this case, what do you want? If I don't give it anything, I will actually get a valid action out of it. So, I can say. We've got to save that in some kind of variable, right?

Can't reference stuff you don't save in variables. And we call it, you will see that I get a valid, actually, I get hand to dispatch. What is even better, thouogh. If I go incrementAction .type, it's because functions are objects, so you can put properties on functions. That is the type.

So all of that kind of ceremony that we used to have to do of like, all right, I'm gonna make a bunch of constants. That's the string in all caps so that I can't mistype it, and my code will now compile if I say success has like 1C or 4Ss in it or something along those lines, you will get this for free.

So now you could actually if you look on increment too. It is also increment. So now, you can pass, later on, you could actually say we'll refactor it right now actually. So, the same function that creates your actions lets you dispatch them, you can also use an irregular reducer, right?

And this will be now the actions that come out of that increment action creator will be of the type increment and the functions type property is also the same. So, now you've removed all of this make constants for the action types, you remove the entire file where you make action creators, all that very chore level stuff that you had to do, gone, right.

And if it does take a payload, the nice part about this one is that payload is not undefined or something, right. It is assuming that the payload on this type of this increment action is in fact not defined because we did not define it. So, if you accidentally tried to call a payload on it, and you're using TypeScript, you get yelled at.

And for the ones where you do define a payload, you will make sure that you're using the right properties with almost no work from yourself. And I love when I get good things with no work. That's the best. We've got this increment and then what we can do is let's say we do want to take some kind of payload, right?

So, action graders I usually use the pattern for making sure we get we want. So, I could say something like Amount is a number. And that will give me back, I do have to format it in the payload, so let's make it a full function so it's clear for everyone.

I can say return an object that has the payload. And you can either say it's the amount like that or you can make it an amount key on an object. Whatever you think you're gonna need, like in this silly example, like I think this is fine. And you already get a hint on the number of squiggly lines that I have down here where things are upset with me.

Which is now I have to call this with a number. And it will know that the payload is a number, so, I get full TypeScript support once again, and again, autocomplete if I'm using JavaScript, no work whatsoever, it's just there for me. And like I said before, this reducer has nothing to do with redox toolkit.

It's just a thing that you can have and use right now and it's battle tested types, it's crazy. There's a conditional now you can go click and look at, it's a lot of fun. And if you really don't even want pull in the dependency, go and steal the types, right?

You can actually do some of these patterns as well. But I think it's a way to figure out a lot of the best practices cuz these are kinda the battle tested agreed upon pieces. And, I am using this on, a sophisticated application right now, and that seem very, brush my shoulder off.

But on a big application, and I can guarantee that it's serves and scales, there's my personal guarantee. So, we have that in place, and now if I said, something like three, you'll see that I get, the correctly typed action. We have all those things in place and it will now know if I say, it now as knows the payload in this case is a number.

Everything is typed, I don't think I wrote a single type in this file. I guess I wrote these ones that I'm not using that were already in the file for counteraction but I didn't write a single type, I've got full TypeScript support in here as well, right? And so, it's kind of interesting we can kind of put all of these things together and have it available for us, and it's all on there and ready to go.

And like I said before, you can use it with anything that you want.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now