Coders Read

Understanding createSlice in Redux Toolkit — ReactJS.

Redux is an open-source JavaScript library for managing application state. It is most commonly used with libraries such as React or Angular for building user interfaces.

Redux Toolkit was introduced with a purpose to be the standard way to write redux logic. It is said to be an opinionated, batteries-included toolset for efficient Redux development. By using this, you can write all the code you need for your Redux store in a single file, including actions and reducers. Using this you can make your code more readable. Redux toolkit includes all the tools, you want for a Redux application. At the end of the day all you have is less code and faster setups of Redux in every scenario.

What is createSlice in Redux Toolkit?

createSlice is a higher order function that accepts an initial state, an object full of reducer functions and a slice name. It automatically generates action creators and action types that correspond to the reducers and state.

In Redux-Toolkit, the createSlice method helps us create a slice of the redux-store. This function aims to reduce the boilerplate required to add data to redux in the canonical way. Internally, it uses createAction and createReducer.

Let’s create a small application to add a location name to the existing list dynamically. This will help to demonstrate on how to implement createSlice, dispatch action and configure store.

Step 1: Implement createSilce method and export actions and reducer.

This step includes creating file which contains the slice. Here we keep the file name as ‘locationSlice.js’.

  • First, import the createSlicemethod from the redux-toolkit library.
  • Make use of createSlice method to create your slice.
  • The locationSlice created above contains all the values required to create a reducer. Now we need to export the actions and the reducer.
import { createSlice } from '@reduxjs/toolkit';
const locationSlice = createSlice({
  name: "location", initialState: {
    location: ['Bangalore', 'Hyderabad', 'Delhi'],
  },

  reducers: {
    save: (state, param) => {
      const { payload } = param;
      state.location = [...state.location, payload];
    },
  }
});

const { actions, reducer } = locationSlice
export const { save } = actions;
export default reducer;

createSlice looks at all the functions that are defined in the reducers field and for every case generates an action creator that uses the name of the reducer as the action type itself.

In the above code, the save reducer created above became an action type of location/save, and the save() action creator will return an action with that type.

Also here we are using the recommended ES6 de-structuring to define the slice and export its action creators and reducers. Although if preferred, we can just directly export the slice object itself, instead of de-structuring and export.

Step 2: Dispatch action by making use of react hooks in functional component.

Now we need to make use of the react hooks useSelector to read the state and useDispatch to dispatch the action created in slice. Let’s implement and see how the app works.

import { useDispatch, useSelector } from "react-redux";
import { save } from "./locationSlice";

useSelector hook will provide us the redux-store object and can be de-structured to get the state values.

useDispatch hook has to be invoked to set up the dispatcher.

const { location } = useSelector(state=>state)
const dispatch = useDispatch();

Here is the final code, when it comes to integrate the above logic to have an app which reads and updates the state value, dynamically.

import React, { useState } from "react";
import { save } from "./locationSlice";
import { useDispatch, useSelector } from "react-redux";
import { Box, TextField, Button } from "@material-ui/core";

export default function App() {
  const [locationName, setLocationName] = useState('');
  const dispatch = useDispatch();
  const { location } = useSelector(state=>state) const handleData = (e) => {
  setLocationName(e.target.value);
}

const handleSave = () => {
  const ifPrestent = location.includes(locationName);
  if(locationName !== undefined && !ifPrestent) {
    dispatch(save(locationName));
    setLocationName('')
  } else {
    setLocationName('')
  }
}

return (
  <Box>
    <Box>
      <TextField
        onChange={handleData}
        value={locationName}
        label="Enter location name"
      />
      <Button
        style={{margin: '10px'}}
        variant="contained"
        color="primary"
        onClick={handleSave}
      >add</Button>               
    </Box>
    <Box>
      <h3> List of locations </h3>
    </Box>
    <Box>
      {location.map((item) => <li>{item}</li>) }
    </Box>
  </Box>
  );
}

Step 3: Configure the store

Now we need to connect our store to the app. Here configureStore({}) wraps createStore() to simplify the configuration for us. createStore() is a redux store that holds the complete state tree of your app.

import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { configureStore } from "@reduxjs/toolkit";
import { Provider } from "react-redux";
import rootReducer from "./locationSlice";

const store = configureStore({
  reducer: rootReducer
});

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);

Finally, this is how the app looks in the browser after the implementation. Try adding new location name and see, if the list of location gets updated dynamically once you click the add button after adding a location name.

Congratulations… You have now learnt how to create and make use of method createSlice of redux toolkit. Using this, you can write all the code required for your redux store in a single file, including actions and reducers, that too in a much more readable way.

. . . . .

Thanks for reading. Hope you gain something from this article.

Sourabh Sinha

Add comment

Follow us

Feel free to get in touch. I love meeting interesting people and making new friends.

Any suggestions will be appreciated.