preface

Hello friends, I share the technology research again, Wuhu ~

This time it’s the Readux Toolkit, which works with the proxy-Memoize I surveyed last time to optimize the current state management of our project.

Redux is a Readux Toolkit that allows users to use the Readux Toolkit. Well, this article may help you with those questions. Of course, if you want to know more about it, you must see the official website.

So without further ado, let’s get to the point

Optimization based on Redux

Readux Toolkit is, of course, a set of optimizations based on Redux. What optimizes Redux? Here’s a quick look at some of the possible drawbacks of Redux (which in some ways are also advantages, depending on the scenario) :

  1. Many of our states should be abstracted to store, and a change should be corresponding to compile actions, reducer
  2. Several packages are needed to make Redux work with React, such as Redux-Thunk and ResELECT
  3. Some of Redux’s ideas led to a lot of boilerplate code
  4. Configuring Redux Store is too complicated

Of course, it is not because of redux’s alleged shortcomings that we have to optimize it. In fact, it is also because of the research on Readux Toolkit that I discovered the shortcomings of Redux. Although it was assigned by the superior, it is still really delicious after the research.

What to know

In order to quickly understand the implementation of Readux Toolkit, you need to understand its core dependencies:

  • immer
  • redux
  • redux-thunk
  • reselect

immer

Immer library immer library immer library immer library immer library

The library, which allows us to convert the immutable property of state to mutable;

Specifically, it uses proxy. When we modify state, the proxy object intercepts and replaces the upper object in order, returning the new object. It looks as if the state has been changed directly for you

api

Let’s take a look at the overall Api and then go into more detail about the ones you might use:

  • configureStore ()Packaging:createStoreTo provide simplified configuration options and good defaults. It can automatically combine your Slice Reducers, add any Redux middleware you provide, and include it by defaultRedux-thunkAnd enable the Redux DevTools extension.
  • createReducer ()This allows you to provide an action type lookup table for the Case Reducer function instead of writing switch statements. In addition, it is used automaticallyimmerLibrary that allows you to write simpler immutable new using normal mutable code, such as state.todos [3].complete = true.
  • createAction (): Generates an action creator function for the given action type string. The function itself is definedtoString (), so you can use it instead of type constants.
  • createSlice (): Accepts the object, file name, and initial state value of the Reducer function, and automatically generates a Slice Reducer with the corresponding action creator and action type.
  • createAsyncThunk: takes an action type string and a function that returns a Promise, and generates a thunk that dispatches according to the Promisepending/fulfilled/rejectedThe action of types
  • createEntityAdapter: Generates a set of reusable reducers and selectors to manage normalized data in storage
  • Reselect the librarycreateSelectorUtility, re-exported for easy use.

configureStore

Step1 is configureStore, which is necessary to create an empty Redux store, and where the Redux DevTools extension is automatically configured to check the storage:

import { configureStore } from '@reduxjs/toolkit'
export const store = configureStore({
    reducer: {},})Copy the code

Step2 is to < provider > to make redux available to the React component, passing the exported store as a prop

createSlice

Create a Redux State Slice using createSlice

  1. A string name identifies the movie
  2. An initial state value
  3. One or more Reducer functions to define how to update this state

What does creating this slice do? You can export the generated Redux action creator and the reducer function for the entire slice:

import { createSlice } from '@reduxjs/toolkit'

const initialState = {
  value: 0,}export const counterSlice = createSlice({
  name: 'counter',
  initialState,
  reducers: {
    increment: (state) = > {
      /** * The Redux Toolkit allows us to write "mutable" logic in a restorer. * It doesn't actually change the state, because it uses the Immer library, * it will detect changes to "draft State "and generate * a brand new immutable state */ based on those changes
      state.value += 1
    },
    decrement: (state) = > {
      state.value -= 1
    },
    incrementByAmount: (state, action) = > {
      state.value += action.payload
    },
  },
})

// Generate action creators for each Reducer function
export const { increment, decrement, incrementByAmount } = counterSlice.actions

export default counterSlice.reducer
Copy the code

Combined with this example, it is clear that the createSlice received a string name identifying the reducer that is name, an initialState value initialState, and a number of reducer rows. Action creators are also generated for each Reducer function.

What does it do or any other benefits? Maybe a few people don’t read the code, so LET me take the comments down.

We know about Redux, which requires us to write all status updates by making copies of data and update copies. However, createSlice and createReducer use Immer internally to allow us to write “mutable” update logic, making it the correct unalterable update.

The Redux Toolkit allows us to write mutable logic in a restorer. It doesn’t actually change the state because it uses the Immer library, detects changes to “draft State” and generates a new immutable state based on those changes

Step 4 We need to import the Reducer function from the empty store created above and add it to our storage. By defining a field in the Reducer parameter, we tell the store to use this slice Reducer function to handle all the updates of this state.

import { configureStore } from '@reduxjs/toolkit'
import counterReducer from '.. /features/counter/counterSlice'

export default configureStore({
  reducer: {
    counter: counterReducer,
  },
})
Copy the code

Now we can use the React-Redux hook to make the React component interact with the Redux store. We can use useSelector to read data from storage and useDispatch to dispatch operations.

To understand, let’s look at this counter component example:

import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { decrement, increment } from './counterSlice'

export function Counter() {
  const count = useSelector((state) = > state.counter.value)
  const dispatch = useDispatch()

  return (
    <div>
      <div>
        <button onClick={()= >Dispatch (increment())} > Increment +</button>
        <span>{count}</span>
        <button onClick={()= >Dispatch (Decrement ())} > Reduce -</button>
      </div>
    </div>)}Copy the code

Action when clicking the + and – buttons, analysis:

  • The corresponding Redux action will be dispatched to store.
  • This counter Slice Reducer will observe actions and update their status
  • The < Counter > component will observe the new state value in the store and re-render itself with the new data

example

Here’s a simple example, you can go to CodesandBox and you can poke it here, and you can go to the website to find this example.

Store. Js file

import { configureStore } from '@reduxjs/toolkit';
import counterReducer from '.. /features/counter/counterSlice';

export default configureStore({
    reducer: {
        counter: counterReducer,
    },
});
Copy the code

CounterSlice. Js file

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

export const slice = createSlice({
    name: 'counter'.initialState: {
        value: 0,},reducers: {
        increment: state= > {
            state.value += 1;
        },
        decrement: state= > {
            state.value -= 1;
        },
        incrementByAmount: (state, action) = >{ state.value += action.payload; ,}}});export const { increment, decrement, incrementByAmount } = slice.actions;

export const incrementAsync = amount= > dispatch= > {
    setTimeout(() = > {
        dispatch(incrementByAmount(amount));
    }, 1000);
};

export const selectCount = state= > state.counter.value;
export default slice.reducer;
Copy the code

Counter. Js file

import React, { useState } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import {
    decrement,
    increment,
    incrementByAmount,
    incrementAsync,
    selectCount,
} from './counterSlice';
import styles from './Counter.module.css';

export function Counter() {
const count = useSelector(selectCount);
const dispatch = useDispatch();
const [incrementAmount, setIncrementAmount] = useState('2');

return (
<div>
    <div>
        <button onClick={()= > dispatch(increment())} >
        +
        </button>
        <span>{count}</span>
        <button onClick={()= > dispatch(decrement())} >
        -
        </button>
    </div>

    <div>
        <input
        value={incrementAmount}
        onChange={e= > setIncrementAmount(e.target.value)}
        />

        <button
        onClick={()= >
        dispatch(incrementByAmount(Number(incrementAmount) || 0))
        }
        >
        Add Amount
        </button>

        <button onClick={()= > dispatch(incrementAsync(Number(incrementAmount) || 0))} >
        Add Async
        </button>
    </div>
</div>
);
}
Copy the code

Index. Js file

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import './index.css';
import App from './App';
import store from './app/store';

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

conclusion

Here is a brief overview of the overall steps of this simple example:

  1. Use configureStore to create a Redux store
    • ConfigureStore accepts the Reducer function as a named parameter
    • The configureStore automatically sets the default Settings
  2. Provide Redux storage to the React application component
    • Wrap the React-redux < Provider > component around the component
    • < Provider store = { store } >
  3. Create a Redux “slice” reducer using createSlice
    • CreateSlice is called with the string name, initial state, and reducer functions
    • The Reducer function may use the Immer “mutate” state
    • Export the resulting Slice Reducer and Action Creators
  4. Use the Redux useSelector/useDispatch hook in the React component
    • Use the useSelector hook to read data from the store
    • Use the useDispatch hook to get the Dispatch function and perform dispatch actions as needed

OK, that’s about it. You’ll notice that there are some major apis that haven’t been covered, such as the very important createReducer and createAction, but this little application can be implemented.

Use Redux Toolkit and React-Redux with TypeScript is not mentioned in this article. In the next part, we will discuss how to use TypeScript with TypeScript and its benefits.

🌸 🌸 🌸 🌸 🌸

Thank you so much for reading this, and if you think it’s good, give it a thumbs up at ⭐

Today is also trying to become strong and bald HearLing 💪

🌸 🌸 🌸 🌸 🌸