DEV Community

Cover image for Writing modern Redux in 2020 - Redux Toolkit
Vitor Capretz
Vitor Capretz

Posted on • Edited on • Originally published at dev.to

Writing modern Redux in 2020 - Redux Toolkit

I wanted to build a React Native app from scratch so I could learn new technologies and find out what I could bring to my workplace and make our app better. Trying out new technologies might be harder to do when you're working in a team for an app that already has millions of users and a couple of hundreds of contributors, such as we do at Klarna.

So I found a React Native tutorial which was simple enough for me to try stuff like react-native-navigation, styled-components and learn how to use Redux in a more modern way.

What do I mean by "Modern Redux"?

In tech, things evolve quickly and new versions of libraries we use on a daily basis are released with a frequency that makes us wonder every once in a while what the cost of updating such libraries is.

Keeping libraries up to date is important for a variety of reasons, e.g. security-vulnerabilities fixes, performance improvements and sometimes even easier implementation.

When talking about React, we recently had a huge update introducing Hooks, which enabled a lot of the libraries in the ecosystem to leverage this approach and to give developers the possibility of moving out from the class approach if they wanted to.

react-redux introduced some hooks too, which I felt was a great addition. The Redux team also introduced @reduxjs/toolkit which is what I'm going to talk about in this post.

Redux architecture and too much boilerplate

Quick disclaimer: I'm not recommending Redux nor am I going to discuss whether it's a good solution for your app, you make that decision according to your own needs and constraints.

When doing the React Native tutorial the author himself was constantly writing the default boilerplate code for setting up a Redux store with its action dispatchers, reducers and a bunch of files for each of these things.

A common approach is to have a folder that contains a file for the actions, a file for the reducer and probably a file for shared constants for action names.

But this causes discussions on whether or not they should be separate files, how you are going to deal with naming conventions, the selectors you're going to declare, etc.

Some other issues when setting up a Redux store also involve remembering not to mutate the store inside the reducers, choosing and setting up middlewares (e.g. for async actions).

Talking to a friend at Klarna about my frustrations and how I was bored just by thinking about all of this, he introduced me to the Redux Toolkit.

What is the Redux toolkit?

The above-mentioned issues (and probably a bunch more) are actually quite common and a lot of people have also shown their frustrations with them. So the Redux team came up with an opinionated toolkit to help us developers move faster by taking some decisions for us whilst making sure we don't break the conventions.

Keep in mind that anything that is opinionated might still bring frustrations for whoever doesn't agree with those opinions, but if they are from the very same people that maintain a library and set the standards for it, I would say it's good enough to trust it and move on so we can focus much more on the users and what they actually need instead of bikeshedding the same problems over and over again.

So the Redux toolkit is an opinionated tool that will handle all the common scenarios for you, removing a lot of the boilerplate code. While it will not solve all the problems you might have with Redux, it does bring benefits to the common scenarios.

Do check their docs for more examples, insights, and reasoning. But let's explore it a bit.

configureStore, createAction and createReducer

To create a simple Redux store you can use these three functions as replacements for the conventional approach.

I'll briefly introduce each of them and then show some code with each of them applied.

  • configureStore replaces createStore, where you can still pass your reducers and middlewares as parameters.
    It provides some useful default middlewares (some of them are applied only in a development environment), redux-thunk is the chosen library as a solution for async actions.

  • createAction removes some of the boilerplate you usually have to write for each action, like the type parameter, how the payload looks and the argument name you will use.
    The action's type is also something you need to share with the reducer so people usually have to set up a constants file to keep track of it.

  • createReducer is the last piece of the puzzle and the one with the most interesting differences compared to the conventional approach.
    Instead of declaring a switch/case for each action type, you can use the actions themselves as parameters and have methods for how each of them should change the store's state.
    Because createReducer uses immer (a library that creates the next immutable state tree while mutating the current one), you can actually mutate the state in any way you want, while still preserving the immutability required by Redux.

Code examples

So now you're probably wondering how all of this is actually implemented. I'll introduce some examples to show the basic scenarios.

The above implementation is one of the most straight forward ones, but it does show the main differences with the conventional approach:

  • While you do have to pass a unique identifier to the actions, you don't need to share them with the reducers. Each action now has a toString method which returns that identifier, so we use that as keys to the reducer object;
  • We pass the initial state as the first parameter for createReducer and an object as the second one;
  • The reducer itself doesn't contain a switch/case statement, each action handler is now a key in an object, we don't need to worry about unknown actions here since it will simply return the current state as it is.
  • Because we are using configureStore, the toolkit is adding some default middlewares for us, you can check the exact ones in the API Reference for getDefaultMiddleware.

This next example shows how we can mutate the state inside each action handler and how the toolkit handles this for us:

Pushing items to an array or modifying a value inside it directly is not recommended when writing conventional Redux, while it's nice to have immutability it may cause more confusion and be less straightforward.

This is what it would look like if you were to avoid direct mutation:

You may or may not agree with this piece of code, but now we have the option to use it.

That's it! With these examples, I hope you now have some understanding of the Redux toolkit. The toolkit also introduces a function called createSlice, I also didn't mention the hooks you can use with React and how to write async actions using redux-thunk.

Let me know if you're interested in those subjects and I’ll write more posts in the future.

Conclusion

This was a short introduction with the goal to document what I discovered about the toolkit and also, hopefully, to spark some curiosity in you.

If you want to know more, please go to the Redux toolkit quick start and then try it out in your application if you're already using Redux.

Please let me know if you have any feedback about this article and follow me on Twitter - @vcapretz to keep in touch!

Cover image by Christian Holzinger on Unsplash

Top comments (6)

Collapse
 
markerikson profile image
Mark Erikson

Hi, I'm a Redux maintainer and creator of Redux Toolkit.

First, thanks for writing this post! It's great to see that folks are trying Redux Toolkit and that it works well for them.

Second, you should really cover createSlice, in this article as well. Most folks won't even need to use createAction or createReducer themselves, because createSlice will call those internally and generate all the action creators and action types for you automatically.

If you've got any other questions, let me know!

Collapse
 
wfelippesilva profile image
William Felippe • Edited

Hi Mark! You said that I can use createSlice to generate the action creators and action types automatically. So in which moment should I use createAction and createReducer?

Collapse
 
markerikson profile image
Mark Erikson

Most of the time, you shouldn't even need to call createAction or createReducer yourself - createSlice is all you'd need.

Collapse
 
vcapretz profile image
Vitor Capretz

Hey Mark! Thank you for reading the article and leaving your feedback! I do think that most people should use createSlice too! I’ll cover that in another post and link it from here ☺️

Collapse
 
chmiiller profile image
Carlos Zinato

Hey Vitor, awesome post, thanks for sharing it, had never heard of redux toolkit and indeed feels boring to start all the redux boilerplate every time!
There is only one thing I wanted to point out though, after the first code snippet, the fourth point is "Because we are using createStore..." I think you actually meant "configureStore" instead isn't it?

Thanks again and great work!

Collapse
 
vcapretz profile image
Vitor Capretz

ha, nice catch! thank you very much, I did mean configureStore

I'm updating the post now 😅