Reduce Redux boilerplate: Slicers

Burak Erdem
4 min readJun 3, 2021

--

It’s been a while since React comes into scene with enhanced capabilities and features that everyone enjoy. But as the famous quote from the famous movie says: “With great power comes great responsibility”. While bringing rich experiences to the users, React also leaves you alone with crucial aspects of such websites or apps. No doubt State Management being the most important one.

When you started your journey in React, chances high that you’ve heard of Redux, the infamous state management library that everybody complains about being “hard” to learn. While this is partially true, the complexity of the library mainly comes from its theoretical concepts and the divided structure which for a newcomer seems very unfamiliar and bizarre. Given that, you should not just only familiarize yourself with the concepts, also write so much boilerplate code even just for a simple data presentation.

Photo by JESHOOTS.COM on Unsplash

Well some time ago, some clever guys noticed the situation and developed a toolkit called Redux Toolkit. Aiming to reduce the burden of the developer, Redux Toolkit comes with a set of tools out of box and simplifies the Redux setup in many ways. This includes configuring the store, automatic thunk injection or other middleware and providing immutability helpers like Immer. One shiny feature of this library is Slicers. These are basically a group of functions replacing actions and reducers at the same time, thus creating a unified bridge for the state. Let’s look into in through an example;

When you implement bare Redux workflow into your app, you probably end up creating actions, reducers and creators in separate folders as this

Too many folders and files

So let’s start converting it to slicers. First we need to install Redux Toolkit

# Yarn
yarn add @reduxjs/toolkit
# NPM
npm install @reduxjs/toolkit

Then create a folder called redux and put store.js inside of it. For the sake of simplicity, I will use only one reducer which is users in my case;

import {
combineReducers,
configureStore,
getDefaultMiddleware,
} from '@reduxjs/toolkit';

import userReducer from '../slicers/users';

const store = configureStore({
reducer: combineReducers({users:userReducer}),
});

export default store;

What we did here is using configureStore we created our store instance and with combineReducers we packaged our reducers. Even there is only one reducer, I intentionally used combineReducers to demonstrate the usage of it. Also keep in mind that Redux Toolkit comes with redux-thunk, so you don’t need to add it separately. Basically, for the most of the time, that’s all you do for the store.

Now let’s dive into the fun part and create slicers. Inside redux folder make slicers folder and inside it create users.js. It’s convenient to have separate files for each state instances. As we have only users, we only create a single slicer. Users.js goes like this;

import {createSlice} from '@reduxjs/toolkit'

const initialState = [];

const userSlice = createSlice({
name: 'users',
initialState,
reducers: {
loadUsers(state, {payload}) {
return payload
},
removeUser(state, {payload}) {
return state.filter(user => user.id !== payload.id)
},
},
})

export const {loadUsers, removeUser} = docSlice.actions;
export default userSlice.reducer;

Let’s breakdown what we did here. First we imported createSlice function to, well, create our slice. Slices take an initialization object in form of

  • name: A name to refer it later when you call from the selectors
  • initialState: Starting state, usually empty
  • reducers: A group of reducer functions

The best part here is that you rid of composing reducers and actions separately and you defined all here in a single file. Reducers are now in form of functions and there are no action creators as Redux Toolkit does automatically generates for you.

Reducers take still state and action parameters and you still need to be careful about immutability concepts. Only thing you do is to export actions and reducer at the same time as in the example.

Well you might be asking “How do I dispatch them?”. Same concepts you would encounter in plain Redux still apply. If you’re using functional components you will use useDispatch hook from react-redux, and connect for class based components. So for example if we want to remove a user, that would be;

import {removeUser} from '../redux/slicers/users';const dispatch = useDispatch();...dispatch(removeUser({id: 1234}));

Notice that we put the payload object directly as we don’t need to create an extra function to pass the state and data. Your editor may complain about the action function should take 2 arguments, and it’s right but our middleware has default thunk function and the state would be passed over without a problem. So you can safely ignore if you’ll have such warning.

Redux, for those who stepped in React world recently, may have terrifying and exhausting setup and concepts, but you can overcome this by using Redux Toolkit and write the code only for what you need. Not to mention reducing also boilerplate and folder structure, your code would also look clean and understandable.

Happy coding!

--

--

Burak Erdem

A technology enthusiast and a senior developer that makes things actually work