Open In App

Why was Redux Toolkit created?

Last Updated : 18 Mar, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

Redux Toolkit was created to improve the overall development experience and to simplify the setup of the redux store and state management tasks. Redux Toolkit is also known as RTK in short. In this article, we’ll discuss the problems that developers face while using Redux and how Redux Toolkit comes up with the solution.

Too much Boilerplate Code

Redux traditionally requires writing a lot of repetitive code for managing state in applications, leading to a poor developer experience and increased chances of errors. Redux Toolkit addresses this issue by providing simpler APIs like configureStore() and createSlice() that reduce boilerplate code significantly. It automatically handles action types and creators, resulting in cleaner and bug-free code, and improving overall development efficiency.

Javascript
// Redux code without Redux Toolkit

const ADD_TODO = 'ADD_TODO';
const REMOVE_TODO = 'REMOVE_TODO';

const initialState = {
    todos: [],
};

function todosReducer(state = initialState, action) {
    switch (action.type) {
        case ADD_TODO:
            return {
                ...state,
                todos: [...state.todos, action.payload],
            };
        case REMOVE_TODO:
            return {
                ...state,
                todos: state.todos.filter(
                    todo => todo.id !== action.payload.id),
            };
        default:
            return state;
    }
}

// Action creators
function addTodoAction(todo) {
    return { type: ADD_TODO, payload: todo };
}

function removeTodoAction(todoId) {
    return { type: REMOVE_TODO, payload: { id: todoId } };
}
JavaScript
// Redux Toolkit code

import { createSlice } from '@reduxjs/toolkit';

const todosSlice = createSlice({
    name: 'todos',
    initialState: [],
    reducers: {
        addTodo: (state, action) => {
            state.push(action.payload);
        },
        removeTodo: (state, action) => {
            return state.filter(
                todo => todo.id !== action.payload.id);
        },
    },
});

export const { addTodo, removeTodo } = todosSlice.actions;
export default todosSlice.reducer;

Accidental state mutation

In the reducer function we can mistakenly mutate the state, which causes a lot bugs and these bugs are hard to debug. See how we can mutate the state in redux. Redux Toolkit works differently to handle this problem, Redux Toolkit uses Immer library to mutate the state. Where syntax looks like we are mutating the state but these are just immutable updates. Immer library internally mutates the state.

Javascript
// Redux code without Redux Toolkit

function todosReducer(state = initialState, action) {
    switch (action.type) {
        case ADD_TODO:
            state.todos.push(action.payload); // Mutating state
            return state;
        default:
            return state;
    }
}
JavaScript
// Redux Toolkit code

import { createSlice } from '@reduxjs/toolkit';

const todosSlice = createSlice({
    name: 'todos',
    initialState: [],
    reducers: {
        addTodo: (state, action) => {

            // Using Immer library to avoid mutation
            state.push(action.payload);
        },
    },
});

Typescript Support

Redux does not provide proper Typescript Support, thus we need to write a lot of type definitions for our code which ultimately results in large boilerplate code and poor code maintenance. Redux toolkit comes with built-in type definitions which means we don’t have to manually write a lot of type definitions which in turn saves a lot of time and code.

Javascript
// Redux code without Redux Toolkit

interface Todo {
    id: number;
    text: string;
    completed: boolean;
}

interface AddTodoAction {
    type: 'ADD_TODO';
    payload: Todo;
}

interface RemoveTodoAction {
    type: 'REMOVE_TODO';
    payload: { id: number };
}

type TodoActionTypes = AddTodoAction | RemoveTodoAction;

function todosReducer(
    state: Todo[] = [], action: TodoActionTypes): Todo[] {
    switch (action.type) {
        case 'ADD_TODO':
            return [...state, action.payload];
        case 'REMOVE_TODO':
            return state.filter(
                todo => todo.id !== action.payload.id);
        default:
            return state;
    }
}
JavaScript
// Redux Toolkit code

import { createSlice, PayloadAction } from '@reduxjs/toolkit';

interface Todo {
    id: number;
    text: string;
    completed: boolean;
}

const todosSlice = createSlice({
    name: 'todos',
    initialState: [] as Todo[],
    reducers: {
        addTodo: (state, action: PayloadAction<Todo>) => {
            state.push(action.payload);
        },
        removeTodo: (
            state, action: PayloadAction<{ id: number }>) => {
            return state.filter(
                todo => todo.id !== action.payload.id);
        },
    },
});

export const { addTodo, removeTodo } = todosSlice.actions;
export default todosSlice.reducer;

Asynchronous Tasks

Performing asynchronous tasks in Redux involves writing complex hard maintainable code which can result in lot of errors. With Redux Toolkit, we can use ‘createAsyncThunk’ which helps in the process of dispatching actions. It reduces the complexity of code in managing async operations. See how simple our code becomes.

Javascript
// Redux code without Redux Toolkit

const FETCH_TODO_REQUEST = 'FETCH_TODO_REQUEST';
const FETCH_TODO_SUCCESS = 'FETCH_TODO_SUCCESS';
const FETCH_TODO_FAILURE = 'FETCH_TODO_FAILURE';

function fetchTodoRequest() {
    return { type: FETCH_TODO_REQUEST };
}

function fetchTodoSuccess(data) {
    return { type: FETCH_TODO_SUCCESS, payload: data };
}

function fetchTodoFailure(error) {
    return { type: FETCH_TODO_FAILURE, payload: error };
}

function fetchTodo() {
    return dispatch => {
        dispatch(fetchTodoRequest());
        fetch('https://api.example.com/todos')
            .then(response => response.json())
            .then(
                data => dispatch(fetchTodoSuccess(data)))
            .catch(
                error => dispatch(fetchTodoFailure(error)));
    };
}
JavaScript
// Redux Toolkit code

import { createAsyncThunk } from '@reduxjs/toolkit';

const fetchTodo = createAsyncThunk('todos/fetchTodo', async () => {
    const response = await fetch('https://api.example.com/todos');
    return response.json();
});


These are the important reasons why the Redux Toolkit was created. You can also check all the other reasons from the documentation, refer to this link: Why Redux Toolkit is How To Use Redux Today



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads