React-redux detailed explanation (take you to learn store, action, redux)

foreword

React has been used for more than a year, but I don’t know much about redux, and I always want to find a chance to master it thoroughly, so with today’s article, if you don’t know enough about redux, you can read it carefully, I believe it will be helpful reward.

Getting to know redux

First let us clarify what is redux? What does it do?

  • redux is an independent JS library dedicated to state management
  • It can be used with react, angular, and vue, but it is mainly used with react
  • Role: Centrally manage the state shared by multiple components in the react application.

redux principle

insert image description here

Describe in words:

Redux stores the state of the entire application in the store, and the view component dispatches the action method in redux .

The action is dispatched to the store through the dispatch method of the store .

The store receives the action and passes it to the reducer together with the previous state .

After the reducer implements the action of updating the state, it returns the new state to the store, and then the store changes its own state.

The view component is connected to the store, and when the state in the store is updated, the data of the view component also changes accordingly, thus re-rendering the page .

Three Principles (Key Points)

1. Single source of truth

The state of the entire application is stored in an object tree, and this object tree only exists in the only store.

Simply put:

An application can only have one store.

When our project becomes more and more complex, we need to split the data processing logic, we can use reducer combination instead of creating multiple store objects

2. State is read-only

The only way to change the state is to trigger (dispatch) action , action is an object that describes what happened, such as clicking a button or something.

3. Use a pure function (reducer) to perform the modification

To describe how actions change the state tree, we need to write reducers

Next, let's learn how to create a store, its corresponding API, and what is a reducer

store

store is the core of redux, responsible for integrating action and reducer.

Redux provides createStore()methods to create a store

import {
    
     createStore } from 'redux'
import reducer from './xxx.ts'

const store = createStore(reducer) // createrStore 接收一个 reducer 为参数

createStoreReceive a reducer as a parameter, it actually has a second parameter, which is optional, and is used to set the initial state of the state

Regarding store, there are three APIs we often use: dispatch, subscribe,getState

dispatch: used to update the state.

      Usage: store.dispatch(action)

      Note: action must be an object, and action.type cannot be omitted.

getState: used to get state

       The getState method is relatively simple, which is to obtain the state, but before returning the state, it will judge isDispatching. If isDispatching is true, it means that it is in the reducer stage. After returning the latest state, assign isDispatching to false.

       When the reducer is in progress, the state cannot be obtained store.getState()by , because we have already passed in the state through (state, action) => {}, and there is no need to obtain it through the getState method. If getState is used in the reducer, an error will be thrown.

subscribe: used to monitor state changes

       Once the state changes, this function will be executed automatically. In fact, after each dispatch, the listener event registered through subscribe will be executed immediately, and we can get the latest state state tree through store.getState in the listener function.

       subscribe returns a function that can be called to unlisten.

useEffect(() => {
    
    
	// 监听 state 的变化
	let unSubscribe = store.subscribe(() => {
    
    
		console.log('我正在监听', store.getState())
	})
	return () => {
    
    
		// 取消监听
		unSubscribe()
	}
}, [])

action

First, let's explain action.

The action is the payload that transfers data from the application to the store, and it is the only source of store data.

We store.dispatch()pass .

Action is essentially a JavaScript common object, which describes the events that have occurred, and its function is to tell the reducer which states in the store should be updated

Action must use a field of type string to represent the action to be executed .type

In most cases, type will be defined as a string constant, usually in uppercase.

{
    
    
	type: 'ADD',
	payload: '测试'
}

{
    
    
	type: 'ADD',
	payload: {
    
    
		text: 'do something'
	}
}

{
    
    
	type: 'ADD',
	payload: new Error(),
	errro: true
}

Except for typethe fields , the structure of the action object is entirely up to us.

In the reducer, different behaviors of modifying the state are executed by receiving different type values ​​of the action.

Generally speaking, it is enough to set the type of the synchronous action . In addition to the necessary type attributes for asynchronous actions , we can also add attributes such as payload, error, and meta.

When there are more and more actions in the system, it is recommended to extract the actions separately into a file.

As shown in the following code example:

store/action/config.js

export const INCREMENT = 'INCREMENT',
export const DECREMENT = 'DECREMENT'

store/action/index.js

import * as constant from './config'

export const incrementNum = () => ({
    
    
	type: constant.INCREMENT,
})

export const decrementNum = () => ({
    
    
	type: constant.DECREMENT,
})
// 优化之前
addNum = () => {
    
    
	store.dispatch({
    
    type: 'INCREMENT'})
}
decreNum = () => {
    
    
	store.dispatch({
    
    type: 'DECREMENT'})
}

// 优化之后

addNum = () => {
    
    
	store.dispatch(actions.incrementNum())
}
decreNum = () => {
    
    
	store.dispatch(actions.decrementNum())
}

reducer

When dispatch initiates an action, it will come to the reducer

The reducer is used to calculate the new store , describing how the action changes the state tree.

reducer is a pure function that receives two parameters, the parameters are the current state and action, and returns a new state.

After the store receives the action, it passes it to the reducer, and the reducer calculates the new state and returns, so that the view will change. This state calculation process is called a reducer.

Note: When using redux for the first time, we need to give state a default value

// 这就是一个 reducer, 这个是 state 是基本类型
const counter = (state = 0, action) => {
    
    
	switch(action.type) {
    
    
		case 'INCREMENT':
			return state + 1
		case 'DECREMENT':
			return state - 1
		default:
			return state
	}
}

// 当 state 为引用类型时
const initState = {
    
    
	number: 0
}
const counter = (state: initValue, action) => {
    
    
	switch(action.type) {
    
    
		case 'INCREMENT':
			return {
    
    
				...state,
				number: state + 1
			}
		case 'DECREMENT':
			return {
    
    
				...state,
				number: state - 1
			}
		default:
			return state
	}
}

let store = createStore(counter)

combineReducers

As the application becomes more and more complex, we can consider splitting the reducer function into multiple separate functions, and each split function is responsible for independently managing a part of the state. At this time, we need to use combineReducers.

combineReducersThe role of the helper function is to synthesize a final reducer function from an object with multiple different reducer functions as value, and then call createStore methods .

give a better example

reducers.js

// reducers.js

export default theDefaultReducer = (state = 0, action) => {
    
    
	switch(action.type) {
    
    
		case 'ADD':
			return state + 1
		case 'DEC': 
			return state - 1
		default:
			return state
	}
}

export firstReducer = (state = 1, action) => {
    
    
	switch(action.type) {
    
    
		case 'ADD':
			return state + 1
		case 'DEC': 
			return state - 1
		default:
			return state
	}
}

export secondReducer = (state = 2, action) => {
    
    
	switch(action.type) {
    
    
		case 'ADD':
			return state + 1
		case 'DEC': 
			return state - 1
		default:
			return state
	}
}

rootReducer.js

// 根reducer 
import {
    
     combineReducers, createStore } from 'redux';

import theDefaultReducer, {
    
     firstReducer, secondReducer } from './reducers'

// 使用了 ES6 的对象字面量简写方式定义对象结构
const rootReducer = combineReducers({
    
    
	theDefaultReducer,
	firstReducer,
	secondReducer
})

const store = createStore(rootReducer);
console.log(store.getState())
// { theDefaultReducer: 0, firstReducer: 1, secondReducer: 2 }

Seeing this, I believe you will have a preliminary understanding of redux, and you will not be as confused as before.

However, the knowledge of redux is more than this, and there are many usages that are not mentioned here. I will add it later when I have a chance, or go to the official website. The official website is the most authoritative place.

Guess you like

Origin blog.csdn.net/qq_41131745/article/details/129186229