DEV Community

Cover image for Writing modern Redux in 2020 - The powerful createSlice
Vitor Capretz
Vitor Capretz

Posted on • Originally published at dev.to

Writing modern Redux in 2020 - The powerful createSlice

In my last post, I wrote a short introduction to Redux Toolkit and its basic functionalities. But I still need to talk about their most important function - called createSlice - which is probably the only one you will need to use for most applications you're writing.

What is createSlice?

If you've ever built an application with Redux you probably ended up with a store that contains multiple reducers, each of them dealing with certain parts of the app. Then you combine all of them in what's usually called a rootReducer, which is then used to create the store itself.

So your store creation would look something like:

Each of these key-value pairs is a "slice" of your application. You can read more about the logic for splitting reducers in the Redux documentation.

createSlice comes in handy because it deals with everything you need for each slice, so instead of calling createAction and createReducer manually, you would use one single function as a replacement.

A basic example would be:

Where the returned object from createSlice will be:

{
  name: "todos",
  reducer: (state, action) => newState,
  actions: {
    addTodo: (payload) => ({type: "todos/addTodo", payload}),
    toggleTodo: (payload) => ({type: "todos/toggleTodo", payload})
  },
  caseReducers: {
    addTodo: (state, action) => newState,
    toggleTodo: (state, action) => newState,
  }
}

So now we've got everything we need:

  • The name parameter will be the prefix for all of your action types,
  • initialState is used for the store;
  • The reducers are again methods in an object, where they can still mutate the state directly - thanks to immer - it works exactly like createReducer;
  • One action is created for each reducer, they all have the same function signature and the type property is derived from the slice name plus the reducer method - like "todos/addTodo" and "todos/toggleTodo";
  • The actions receive only a "payload" parameter, which is recommended according to the Flux Standard Action pattern. If you need to pass in more than one parameter, put them in an object.

Working with multiple slices

Most projects will contain many slices, it's a nice approach to separate them by features so they contain smaller logic for handling each part of the store. For these projects createSlice is probably all you're going to need, where each slice should be in separate files containing a default export for the reducer and named exports for the actions.

Putting it all together you would end up with something like:

Conclusion

Since Redux Toolkit is an opinionated tool and Redux has been more explicit about what rules you should follow and how you should structure your app, you can have the peace of mind that your apps are going to follow those rules by default.

I believe that now we are all able to write better applications with Redux, removing a lot of the boilerplate code we wrote in the past years and making it easier to maintain our codebases. Software development keeps evolving and sometimes it's natural we need to learn new things. I hope now you have enough information to start using Redux Toolkit in your projects!

Please check this page with a step by step guide on how to migrate to the new approach. And if you want to understand more deeply about some of the guidelines mentioned in this article check the Redux Style Guide page.

All feedback is welcome! Comment below if you have any questions and like the post if you enjoyed reading it 😄

Feel free to follow me - @vcapretz - on Twitter to keep in touch, my DM's are always open!

Thank you Erik Engervall for reviewing the post for me!
Cover photo by Денис Евстратов on Unsplash

Top comments (2)

Collapse
 
markerikson profile image
Mark Erikson

Very nice!

One additional bit: as with createAction, you can define a "prepare callback" function that can be used to turn multiple arguments into the payload field, generate unique IDs, or whatever other consistent prep work needs to be done for the action:

const todosSlice = createSlice({
  name: 'todos',
  initialState: [], 
  reducers: {
    addTodo: {
      prepare(text) {
        const id = uuid();
        return {payload: {id, text}};
      },
      reducer(state, action) {
        const { id, text } = action.payload
        state.push({ id, text, completed: false })
      }
    }
  }
})
Collapse
 
cleverzone profile image
Abhijeet kumar

That's huge