preface

First of all, I used to be a VUE developer, so I have experience in using Vuex. Although I can get started quickly, I may be limited by the framework burden in order to write today’s article, I have read a lot of documents.

First of all, just to make fun of it, when I first looked at this document, the Redux Chinese document, I thought, is this Chinese document really for humans? I might as well read the English document. I know every word, but I can’t read it together.

Later I learned that the above is not the official website, this redux Chinese official website is the original. If the needle does not poke, the pit will be trampled at the beginning.

Today is the seventh day of learning React. My first small goal is to implement all functions of the todo manifest software I usually use on the Web side with React one-to-one!

📦 repository links to the React-Todo Gitee repository

💻 Online preview Effect React-Todo development progress

Create React App+Tailwind CSS +Material UI

# 👀 learn React from the ground up next day ~React configure Eslint+ router-dom

# 👀 Learn React from scratch 3 days ~React date selector component development +Dayjs use

# 👀 Start from scratch learn React day 4 ~📆 implement a nice popover calendar component

# 👀 learn React from scratch day 5 ~📈 implement hook related performance optimization

Redux introduces

The official introduction is as follows:

Redux is a pattern and tool library that uses events called actions to manage and update application state. It centrally manages state used throughout the application in a centralized Store, with rules that ensure that state can only be updated in predictable ways.

My understanding is that you can isolate variables in your project that need to be used by multiple components and maintain them separately in a repository.

For example, if you create a 👴 grandparent with many variables, its 👶 grandchild needs to use several of these variables, but its 👦 child does not, but if you want to pass this variable you have to modify the child to pass through it.

Or many variables of the grandpa component need to add a brother 👨🦳 two grandpa component, it needs to use the grandpa component variable, then we can only put this variable into grandpa and two grandpa’s parent component 👼 grandpa component go there.

If your entire project has multiple components that need to share and use the same variables, you can only put them all in the oldest component in the 🐵 family tree

In Redux, the variables in your project are managed in a single location, and the variables in the whole component family tree are placed in a sorted repository, so that anyone who wants a value can directly get it

The rest of the article will expand on the examples above and my TODO list project to illustrate Redux more visually. Install Redux and execute the following commands

The Redux Toolkit is the official Redux development tool set out of the box. The following examples are developed using the Redux API.

Concepts and Usage

Next we talk about concepts while developing, so that we can pay equal attention to theory and practice, remember to eat with catalog!

The word variable has always been used, but it should actually be called the state of the data, just to make it easier to understand

ConfigureStore () : Creates a repository

The first thing we definitely need is a way to create the repository. In Redux we use configureStore()

The Redux Store is created using the configureStore function of the Redux Toolkit. The configureStore requires that we pass in a Reducer parameter.

//index.js
import { configureStore } from "@reduxjs/toolkit"
export default configureStore({
    reducer: {
        // Put the modules here}})Copy the code

Now that the warehouse is set up, how do we put stuff in it? The first thing to understand is that we can’t clutter things up in the warehouse. What’s the difference if we clutter things up?

What we need to do is to classify the warehouse for storage, and each class in the classification is the concept of slice in Rudex.

Slice: warehouse classification

Slice Reducer is similar to vuEX module, that is, separate the warehouse in a row, easy to put and easy to find!

“Slice” is a collection of Redux Reducer logic and actions for a single function in an application, usually defined together in a file. The name comes from splitting the root Redux state object into multiple state “slices.”

The method to create a slice is createSlice(), as follows:

import { createSlice } from "@reduxjs/toolkit"

export const slice = createSlice({
    name: "date".initialState: {
        activeDate: dayjs(),
    },
    reducers: {
        setActiveDate: (state, action) = > {
            state.activeDate = action.payload
        },
    },
})

export const { setActiveDate } = slice.actions
export default slice.reducer

Copy the code

In this case, we can see that we created a slice in which the initialState should not be difficult to understand, which is the basic data in the warehouse. But what are Reducer and Action?

Reducer: Warehouse administrator

Reducer can be understood as the warehouse-manager. If you want to save, change or throw data, Reducer must go through its hands

Reducer has the following principles:

Calculate the new state value using only the state and action arguments.

Do not modify state directly. Immutable updates must be made by copying existing state and making changes to the copied values.

Disallow any asynchronous logic, reliance on random values, or code that causes other “side effects.

Although you are the warehouse administrator, but you can not be disorderly, you can only follow the rules to take data, so we promulgate a warehouse management code of conduct Action, warehouse management can only act according to the rules.

Action: Warehouse code of Conduct

Action can be understood as a warehouse code of conduct, represented in code as a plain JavaScript object with a Type field.

const getApple = {
    type: 'Apple warehouse/Get red apples'
}

const setApple = {
    type: 'Apple warehouse/Red apples'.payload: 'Red Apple'
}
Copy the code

The Reducer repository administrator can only perform specified actions based on the current repository based on the type of actions the repository behavior code is passed in by the component

Reducer is a pure function that calculates the new state based on the previous state and action

UseSelector () : Warehouse finder

The inventory of the warehouse can be found through the warehouse finder

The React component uses the useSelector hook to read data from the Store

The selector function takes the entire state object and returns the required part of the data

Every time the Redux Store is updated, the selectors will re-run, and if the data they return changes, the components will be re-rendered

In short, it is used to get the specified module data as follows:

import { useSelector } from "react-redux"
/ /...
const dateState = useSelector((state) = > state.apple)
Copy the code

It’s just a way to take out the modules that we’re shard, easy to understand.

UseDispatch () : transmits the rules of behavior

UseDispatch () is an action that sends a warehouse behavior code action to the Reducer repository manager if the component wants to perform some action on the repository.

The React component uses the useDispatch hook dispatch Action to update the Store

Call Dispatch (someActionCreator()) in the component to dispatch the action

The usage method is as follows:

import { useDispatch } from "react-redux"
/ /...
const dispatch = useDispatch()
const setDate = (date) = > dispatch(setActiveDate(date))

onClick={() = > {
      setDate(item)
}}
Copy the code

Immutability: Immutability

Immutable means that the warehouse manager cannot directly change the data in the warehouse, but can only make a copy of the data and then modify it. For example, after the warehouse administrator manipulates the warehouse data, he will tell the component over the loudspeaker “There is a change in the warehouse data, please check if it is different from the previous data”. The component determines whether the new data in the repository is the same as the old data in the repository, and if the component determines that the data has been updated it rerenders or performs some action. However, if the warehouse administrator directly modifies the data, then the component has no way to determine whether the data is old or new, resulting in the data changing but the component does not render the new data.

From the perspective of code, arrays and objects in JS are reference types, so when we modify the referenced data, the original data will also change, which makes it impossible to determine whether a new data is different from an old data. This is easy to be trashed in react or vue’s responsive implementation.

Here are a few reasons why you can’t change state in Redux, as mentioned in the official documentation:

  • It can cause bugs, such as the UI not updating properly to display the latest values
  • It’s harder to understand why and how status updates are made
  • Writing tests becomes more difficult
  • It breaks the ability to use “time travel debugging” properly

The correct way to do this is to modify the entire object or array directly:

To update in an immutable manner, the code must first copy the original object/array and then update its copy.

const obj = {
    a:1.b:2
}
//bad 
obj.b = 3

//goodobj = {... obj,b:3}

Copy the code

When creating slices using the createSlice() API, the method used in the parameter Reducers property we passed in can directly change state because createSlice uses a library called Immer internally to help us convert updates to immutable new, This is a lot more convenient

Unidirectional data flow

One-way data flow means that the component only has permission to fetch resources according to different warehouse classifications. Components must follow the rules. They cannot go to the warehouse themselves to manipulate data. They must send a code of conduct to the warehouse administrator to help you operate in the designated warehouse.

In the warehouse, of course, if the change will inform you need to use the resources of the component Warehouse in the new state of resources, this step should be done by publish-subscribe, components used in data warehouse will subscribe to the specified event, the data used in the component changes will inform all subscribe to the component rendering with new data.

Subscribe (Listener) API is available in the documentation, but it has not been used in the actual development of the scenario. It should be integrated in some packages

The official chart is particularly good, and will be even more graphic if you have some understanding of redux’s data flow.

Of course, there are also personal Chinese version 💩 :

Project reform

In terms of actual use, I will adapt it to my TODO list project and gradually extract the data originally written in components into Redux.

First install the following corresponding packages:

yarn add redux react-redux @reduxjs/toolkit
Copy the code

The directory structure

Create a store directory in the root directory, and create index.js and modules directories in store. Modules directory is used to store our shard files. Index.js is the entry file.

We will create a new module in modules called date.js. This module is used to remove the selected date activeDate from the date selection bar for reuse

Create a slice

Create a new slice using createSlice in date.js and pass in the parameters. CreateSlice not only creates the slice for us, but also creates the corresponding Reducer and warehouse actions for us in advance

// store/modules/date.js
import { createSlice } from "@reduxjs/toolkit"
import dayjs from ".. /.. /utils/day"
export const slice = createSlice({
    name: "date".initialState: {
        activeDate: dayjs(),
    },
    reducers: {
        setActiveDate: (state, action) = > {
            state.activeDate = action.payload
        },
    },
    
})

export const { setActiveDate } = slice.actions
export default slice.reducer

Copy the code

Create a warehouse

Next we create a repository, place the slice in the repository, and write the following code in store/index.js:

// store/index.js
import { configureStore } from "@reduxjs/toolkit"
import date from "./modules/date"
export default configureStore({
    reducer: {
        date,
        // Put the modules here
    },
    middleware: (getDefaultMiddleware) = >
        getDefaultMiddleware({
            serializableCheck: false,})})Copy the code

I’ve also turned off serialization checks through the middleware configuration items, which I haven’t used yet to extend Redux’s functionality, so I just changed the configuration. I turned serialization checking off because my warehouse data is a DayJS () object, which keeps reporting errors when it’s closed.

Into the store

We then use the React-redux Provider to wrap the root component in the project’s index.js directory and pass in the store

Any React component that calls useSelector or useDispatch can access store in .

// index.js
import React from "react"
import ReactDOM from "react-dom"
import "./index.css"
import App from "./App"
import reportWebVitals from "./reportWebVitals"
import { BrowserRouter } from "react-router-dom"

import store from "./redux/index"
import { Provider } from "react-redux"

ReactDOM.render(
  <Provider store={store}>
    <BrowserRouter>
      <React.StrictMode>
        <App />
      </React.StrictMode>
    </BrowserRouter>
  </Provider>.document.getElementById("root")
)
reportWebVitals()
Copy the code

Modify the code

Change the variable that was created using useState to use useSelector to get slices, then use useDispatch to create the Dispatch, and dispatch the action using the Dispatch

//old
const [activeDate, setDate] = useState(dayjs())

//new 
import { useSelector, useDispatch } from "react-redux"
import { setActiveDate } from ".. /.. /redux/modules/date"

const activeDate = useSelector((state) = > state.date.activeDate)
const dispatch = useDispatch()
const setDate = (date) = > dispatch(setActiveDate(date))
Copy the code

This allows me to add the activeDate variable to any component, so that I don’t have to modify the original component even if the component continues to grow and the business continues to expand

Here is not screenshots of the page effect, the final page effect is unchanged, but for the future development efficiency is very helpful.

conclusion

For a developer with vuex experience, Redux is quite different. The main reason is that VUex has done so much work for us that we are unfamiliar with many terms in this kind of state management library. After writing this article, I am greatly reminded and my development thinking has been improved a lot.

Learn react series from scratch has been a week, will speed up the development progress, after all the development is complete a wave of summary!

If you think this article is helpful to you, please give a thumbs up. Your encouragement is the biggest motivation for my creation