React is a super fast, reliable Javascript framework for single page applications with responsive UI. React and Redux work perfectly together. Redux is a very flexible immutable state management tool built for performance and customization. Redux helps to keep track of the state and data for React screens and components.

Setting up Redux with React could feel like a very confusing and complicated process. There are many packages to install and writing quite a bit of boiler plate code is needed to get redux to do anything. That’s where Redux Toolkit steps in.

Redux Toolkit very is simple to setup, it provides immutable update logic and warnings if your state mutates outside the state. The toolkit allows to merge the state object many levels deep through a proxy by just assigning a value to an object. You no longer need to use spread operator to merge the objects:

Before:

state = {
  user: {
    firstName: 'User',
    lastName: 'Last',
    ...newUser,
  groups: {
    sales: true,
    hr: false,
    admin: false,
    ...newUser.groups
  }
}

After:

state = _.deepMerge(state, newUser);

Redux Toolkit provides a very useful feature that allows to create the whole state management in one call and keep all of the logic and actions in the same place. There is no need to separate actions and reducers into separate files.

Instead of:

const increment = createAction('INCREMENT')
const decrement = createAction('DECREMENT')

const reducer = createReducer(0, {
  [increment]: state => state + 1,
  [decrement]: state => state - 1
})

 

Now we can do:

const counterSlice = createSlice({
  name: 'counter',
  initialState: 0,
  reducers: {
    increment: state => state + 1,
    decrement: state => state - 1
  }
})

const {
  increment,
  decrement
} = counterSlice.actions;

const reducer = counterSice.reducer;

 

createSlice allows us to configure all the actions as functions and define actions as functions and control types of passed functions, which is a must when working with Typescript. With Redux Toolkit, we can create  a completely type safe state and actions.

Here is an example:

import { createSlice, PayloadAction } from 'redux-starter-kit';
import { CompanyParams } from '../../schema/company';
import * as StateHelpers from '../../redux/stateHelpers';
import _ from 'lodash';

interface CompaniesState {
  companiesStatus: StateHelpers.StateStatusProps,
  activeCompanyId: string,
  companies: CompanyParams[],
}

const initialState: CompaniesState = {
  companiesStatus: null,
  activeCompanyId: null,
  companies: [],
};

const findIndex = (companies: CompanyParams[], searchId: string) => {
  return _.findIndex(companies, company => {
    return company.id === searchId;
  });
};

const companies = createSlice({
  name: 'companies',
  initialState: initialState,
  reducers: {
    updateStatus(state, action: PayloadAction<Partial<StateHelpers.StateStatusProps>>) {
      state.companiesStatus = StateHelpers.updateStatus(state.companiesStatus, action.payload);
    },

    saveCompanies(state, action: PayloadAction<CompanyParams[]>) {
        state.companies = action.payload;
        state.companiesStatus = StateHelpers.updateStatus(state.companiesStatus, {status: StateHelpers.StateStatuses.FETCHED});
    },

    saveCompany(state, action: PayloadAction<CompanyParams>) {
      const company = action.payload;
      const index = findIndex(state.companies, company.id);
      const companies = _.cloneDeep(state.companies);
      if (index >= 0) {
          if (!_.isEmpty(company.deleted)) {
              companies.splice(index, 1);
          } else {
              companies[index] = company;
          }
          state.companies = companies;
      }
      else if (company.id && _.isEmpty(company.deleted)) {
          companies.unshift(company);
          state.companies = companies;
      }
    },
    updateCompany(state, action: PayloadAction<Partial<CompanyParams>>) {
      const company = action.payload;
      const index = findIndex(state.companies, company.id);
      const companies = _.cloneDeep(state.companies);
      if (index >= 0) {
          companies[index] = {...companies[index], ...company};
          state.companies = companies;
      }
    },
    selectCompany(state, action: any) {
      state.activeCompanyId = action.payload;
    }
  }
});

export const {
  updateStatus,
  saveCompanies,
  saveCompany,
  updateCompany,
  selectCompany,
} = companies.actions

export default companies.reducer;

 

Redux Toolkit is very opinionated framework forcing developers to follow the guidelines and write the code in a similar manner thus simplifying maintenance and training. The Typescript support helps to minimize errors and testing by enforcing concrete types.

Contact us today for any React, React Native, or Redux support.