What is the story

  1. Rduex is a JS library for state management (note: not the React plugin library).
  2. It can be used in any framework, as well as native JS, but mostly works with React
  3. Role: Centrally manages the state shared by multiple components

Redux principle

Look at the picture is very abstract, need to use a life example to vividly express, estimate can understand more deeply.

For example: I am hungry, go to a restaurant to eat, I give the waiter said I want an egg fried rice, and then the waiter to the menu to the restaurant owner, the boss informed the chef to do an egg fried rice, the chef to finish fried after the meal to the boss, and then I go to take the meal.

Now, I am React Components, the waiter is Action Creators, the restaurant owner is Store, and the chef is Reducers.

See, Redux is such a workflow, doesn’t it feel like life?

That is: Action defines the state, Dispatch dispatches the state, Store executes, Reducers executes, reducers returns a new state, and getState updates the view

Redux has three core concepts

1. action

  1. Object of action
  2. Contains two properties
    • Type: Identifies the attribute. The value is a string, unique, required attribute
    • Data: Data attribute. The value type is arbitrary and optional
  3. Example: {type: “ADD_USER,” data: {name: “Wangpf”, the age: “18”}}

2. reducer

  1. Used for initialization state, machining state.
  2. During processing, pure functions of the new state are generated based on the old state and action

3. store

The object that links state, Action, and Reducer together

Let’s start with a small example to illustrate the simple version of Redux

Steps to use redux

  1. Create a reducer. Js
    • The essence of renducer is a function that receives preState,action, and returns the state after processing
    • Renducer has two functions: initialization state and processing state
    • Note: Store automatically triggers renducer when it is called for the first time
      • The preState passed is undefined
      • The action passed is: {type:” @@redux/init_D.5.f.4 “} something like this
    • Through dispatc (aciton), put state ({type,data}) into the Reducer function for processing, and return the new state.
  2. Create a store. Js
    • Into reduxcreateStoreMethod to create a store
    • createStoreCall with a Reducer that is its service
    • Is used in this filecreateStore API
  3. Introduce a store in the component
    • Use getState, Dispatch, Subscribe apis to implement status updates.

Test knife, according to the above steps, the corresponding code is as follows:

// count_reducer JS file
function countReducer(preState =0, action) {
  const { type, data } = action
  const typeMap = {
    "increment": preState + data,
    "decrement": preState - data
  }
  if (type in typeMap) {
    return typeMap[type]
  } else { 
    return preState
  }
}
export default countReducer
Copy the code
// store js file
import { createStore } from 'redux'

import countReducer from './count_reducer'

export default createStore(countReducer)
Copy the code
// Component method code

// render 

summation: {store.getstate ()}

componentDidMount() { store.subscribe(() = > { this.setState({}) }) } / / add increment = () = > { const { value } = this.currentNum store.dispatch({ type: "increment".data: value * 1})}/ / subtraction decrement = () = > { const { value } = this.currentNum store.dispatch({ type: "decrement".data: value * 1})}Copy the code

We haven’t used the action concept yet, so let’s optimize our code:

Optimization steps:

  1. Create action. Js
    • It is used to record the actions of the user
    • Specifically used to create action objects
  2. Create constant. Js
    • Use variables to control type in actions to unify management and prevent word errors

The code looks like this (I put it together) :

// constant.js 
// This module is used to define constant values of type type in action objects. The purpose is to facilitate management and prevent word errors
export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'


// action.js 
import { INCREMENT,DECREMENT} from './constant'

export const createIncrementAction = data= > ({ type: INCREMENT, data})
export const createDecrementAction = data= > ({ type: DECREMENT, data})


// Reducer.js code part optimization
// Change the original string to the variable name
 const typeMap = {
    [INCREMENT]: preState + data,
    [DECREMENT]: preState - data
  }
  
// Component implementation method code optimization
  increment = () = > {
    const { value } = this.currentNum
    store.dispatch(createIncrementAction(value * 1))
  }
  decrement = () = > {
    const { value } = this.currentNum
    store.dispatch(createDecrementAction(value * 1))}Copy the code

That’s a simple process for how to use Redux.

Asynchronous action

If we do not want to defer actions to the component itself (that is, asynchronous operations do not want to be implemented within the component), we want to delegate actions to handle them.

When asynchronous action is required: You want to operate on the state, but the specific data is returned by an asynchronous task.

Specific steps:

  1. NPM install redux-thunk and configure it in store
import { createStore,applyMiddleware } from 'redux'
// Support asynchronous actions
import thunk from 'redux-thunk'
export default createStore(countReducer,applyMiddleware(thunk))
Copy the code
  1. The function that creates the action no longer returns a generic object, but a function, because functions can write asynchronous tasks.
  2. After the asynchronous task has a result, publish a synchronous action to actually manipulate the data

The case code is as follows:

// action.js
// To handle asynchrony it must return a function
export const createIncrementAsyncAction = (data,time) = > { 
  return (dispatch) = > {
    setTimeout(() = > {
      dispatch({ type: DECREMENT, data })
     },time)
   }
}

// within the component
  incrementAsync = () = > {
    const { value } = this.currentNum
    store.dispatch(createIncrementAsyncAction(value * 1.500))}Copy the code

Conclusion: We can wait for the results of asynchronous tasks before publishing synchronous actions, so we feel that the asynchronous action is not important.

react-redux

Two concepts need to be clarified:

  1. UI component: can not use any render API, only responsible for page rendering, interaction, etc., state is completely external control.
  2. Container component: Responsible for communicating with Redux and passing the results to the UI component.

Two cores need to be identified:

The Provider and the connect

Provider

The purpose of a Provider is to make data in redux accessible to all components.

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

connect

First, it works like this:

connect(mapStateToProps, mapDispatchToProps)(component)
Copy the code

mapStateToProps:

  • Map state to props.
  • Mapping state, the return value is an object
// Container components:
function mapStateToProps(state) {
  State = {a:123}
  return { foo: state.a }
}

// UI component:
render(){
 return (
  <div>{ this.props.foo }</div>  / / 123)}Copy the code

MapDispatchToProps:

  • Map various dispatches to props for you to use
  • A method that maps the state of an operation and returns an object
// Container components:
function mapDispatchToProps(dispatch) {
  return {
     add: number= > dispatch({type:"increment"},number),
  }
}

// UI component:
<button onClick={this.props.add(1)}> + </button>
Copy the code