In this paper, react Family barrel products are very refined to extract the core content, the essence level is comparable to essential oil. Ladies and gentlemen, since you are here, take a seat for the guest officer. Somebody, give the guest officer tea ~~

redux

preface

First of all, this article requires you to have some knowledge of JS and React. If you don’t know react, you should read it first. A complete summary (Rush)

React has props and state:

  1. Props means properties that are distributed by the parent
  2. State means the state that can be managed internally by the component, and the entire React does not have the ability to trace data upward. This is the one-way data flow of React

This means that if it is a very complex application data status, more found the React cannot let two components communicate with each other, using each other’s data, the React of transfer data through the hierarchy of this method is very uncomfortable, this time, the urgent need for a mechanism to put all of the state on the top of the component, Having the flexibility to distribute all the states as needed to all the components, yes, that’s Redux

Introduction to the

  1. Redux was created to provide “predictable state management” for React applications.
  2. Redux stores the entire application state (that is, data) in a single place called a Store
  3. There’s a state tree in this store.
  4. The only way for a component to change state is by calling the Store’s Dispatch method, which triggers an action that is processed by the corresponding Reducer, and state completes the update
  5. Components can dispatch actions to stores instead of notifying other components directly
  6. Other components can refresh their views by subscribing to states in the Store

Using the step

  1. Create the reducer
    • A single reducer can be used, or multiple reducers can be combined into a reducer, that is:combineReducers()
    • Action puts the state into the Reucer processing function after issuing the command, returns the new state, and processes the state
  2. Create an action
    • State is not accessible to users, but can only be triggered by the view. Therefore, this action can be understood as an instruction, and there are as many instructions as need to be issued
    • Action is an object and must have a parameter called type that defines the action type
  3. Create a store using the createStore method
    • Store can be understood as a total factory with multiple processing machines
    • Subscribe, dispatch, and getState methods are provided.

Step by step.

The sequence number of the above steps will be marked in the relevant code

npm install redux -S / / installation

import { createStore } from 'redux' / / introduction

const reducer = (state = {count: 0}, action) = >{-- -- -- -- -- -- -- -- -- -- > (1)switch (action.type){
    case 'INCREASE': return {count: state.count + 1};
    case 'DECREASE': return {count: state.count - 1};
    default: returnstate; }}constThe actions = {-- -- -- -- -- -- -- -- -- -- > 2 happens:(a)= > ({type: 'INCREASE'}),
  decrease: (a)= > ({type: 'DECREASE'})}conststore = createStore(reducer); -- -- -- -- -- -- -- -- -- -- > (3) store. The subscribe ((a)= >
  console.log(store.getState())
);

store.dispatch(actions.increase()) // {count: 1}
store.dispatch(actions.increase()) // {count: 2}
store.dispatch(actions.increase()) // {count: 3}
Copy the code

I drew a very simple flowchart to understand the redux workflow

react-redux

React (props) If the store is integrated directly into the React props, all the sub-components need to be able to access the props.

Store ={store}> <App /> </ store >Copy the code

Isn’t that ok? That’s react-redux. Redux provides the React binding library. It is efficient and flexible.

React Redux distinguishes components into container components and UI components

  1. The former handles logic
  2. The latter is only responsible for display and interaction, and does not handle logic internally. The state is completely controlled externally

Two core

  • Provider

    Look at the top component of my code up there four words. Yes, you guessed right. The top component is the Provider. We usually wrap the top component in the Provider component, so that all components can be controlled by react-Redux, but stores must be placed as arguments in the Provider component

    <Provider store = {store}>
        <App />
    <Provider>
    Copy the code
    The purpose of this component is for all components to have access to the data in Redux.Copy the code
  • connect

    This is the hard part of React-Redux, so let’s explain it in detail

    First, remember this line of code:

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

    mapStateToProps

    Map state to props (); map data from Redux to props ();

    Here’s an example:

    const mapStateToProps = (state) => {
      return{/ / prop: state. | means XXX will be one of the state data is mapped to the props in the foo: state. The bar}}Copy the code

Then you can render using this.props. Foo

class Foo extends Component {
    constructor(props){
        super(props);
    }
    render() {return<div>this.props. Foo </div>)}} foo = connect()(foo);export default Foo;
Copy the code

Then you can finish rendering

mapDispatchToProps

The word translates as props for all kinds of dispatches that you can use directly

Const mapDispatchToProps = (dispatch) => {// The default pass parameter is dispatchreturn {
    onClick: () => {
      dispatch({
        type: 'increatment'}); }}; }Copy the code
class Foo extends Component {
    constructor(props){
        super(props);
    }
    render() {return(<button onClick = {this.props. OnClick}> increase</button>)}} Foo = connect()(Foo);export default Foo;
Copy the code

You can call dispatch directly with this.props. OnClick, so you don’t need to store

That concludes the basic introduction to React-Redux

redux-saga

If the original redux workflow is followed, reducer modification state will be directly triggered when an action is generated in the component. Reducer is a pure function, that is, no asynchronous operation can be performed in reducer.

In practice, an asynchronous task needs to be completed before the actions in the components enter the reducer, such as sending ajax requests and receiving data, and then entering the reducer. Obviously, native Redux does not support this operation

There is an urgent need for middleware to handle this business scenario, and redux-Saga is by far the most elegant solution

Interpretation of the core

1. Saga auxiliary function

Redux-saga provides helper functions for deriving tasks when certain actions are initiated to the Store. I’ll start with two helper functions: takeEvery and takeLatest

  • takeEvery

TakeEvery is just like a dishwasher on an assembly line. Once you get a dirty plate, he will directly perform the following dishwashing function. Once you hire this dishwasher, he will always perform this work and will never stop the monitoring process of receiving dishes and trigger the dishwashing function

For example, every time a button is clicked to Fetch data, we issue a FETCH_REQUESTED action. We want to process this action by starting a task to get some data from the server, something like this

window.addEventLister('xxx',fn)
Copy the code

When dispatch XXX is executed, the fn method is executed,

First we create a task that will execute an asynchronous action (fn above) :

// put: you can say put equals dispatch; // call: an asynchronous function that blocks until the next function is run. // await in async! But it's much more intuitive! import { call, put } from'redux-saga/effects'

export function* fetchData(action) {
   try {
      const apiAjax = (params) => fetch(url, params);
      const data = yield call(apiAjax);
      yield put({type: "FETCH_SUCCEEDED", data});
   } catch (error) {
      yield put({type: "FETCH_FAILED", error}); }}Copy the code

The above task is then started each time a FETCH_REQUESTED action is triggered, which means that the above task will be executed each time an action named FETCH_REQUESTED is triggered

import { takeEvery } from 'redux-saga'

function* watchFetchData() {

  yield* takeEvery("FETCH_REQUESTED", fetchData)
}
Copy the code

Note: The above takeEvery function can be replaced with the following

function* watchFetchData() {
  
   while(true){
     yield take('FETCH_REQUESTED'); yield fork(fetchData); }}Copy the code
  • takeLatest

In the example above, takeEvery allows multiple fetchData instances to be started at the same time, and ata certain point we can start a new fetchData task, even though one or more fetchData instances have not yet been completed

If we just want the response to the latest request (for example, always show the latest version of the data), we can use the takeLatest helper function

import { takeLatest } from 'redux-saga'

function* watchFetchData() {
  yield* takeLatest('FETCH_REQUESTED', fetchData)
}
Copy the code

Unlike takeEvery, takeLatest allows only one fetchData task to be executed at any one time, and that task is the last one to be started. If there is already a task in progress, that task is automatically cancelled

2, the Effect of Creators

The Redux-Saga framework provides a number of functions for creating effects, so let’s take a quick look at some of the most commonly used in development

  • take(pattern)
  • put(action)
  • call(fn, … args)
  • fork(fn, … args)
  • select(selector, … args)

take(pattern)

The take function, which can be understood as listening for future actions, creates a command object that tells middleware to wait for a specific action, and the Generator pauses until an action matching pattern is initiated. In other words, Take is a blocking effect

Usage:

function* watchFetchData() {
   while(true) {// listen on onetypefor'FETCH_REQUESTED'FetchData (fetchData), which executes the following yield fork(fetchData) statement:'FETCH_REQUESTED'); yield fork(fetchData); }}Copy the code

put(action)

Put is an effect that sends an action. You can think of it simply as a Dispatch function in the Redux framework. When an action is put, the reducer will calculate the new state and return it

Usage:

export function* toggleItemFlow() {
    letList = [] // Send onetypefor'UPDATE_DATA''data: list' yield PUT ({data: list 'yield put({type: actionTypes.UPDATE_DATA,
      data: list
    })
}
Copy the code

call(fn, … args)

Call is a function that can call other functions. It commands middleware to call fn (args). The fn function can be a Generator or a normal function that returns a Promise, and the call function is also a blocking effect

Usage:

export const delay = ms => new Promise(resolve => setTimeout(resolve, ms))

export function* removeItem() {try {// The call function calls the delay function, which returns a promisereturn yield call(delay, 500)
  } catch (err) {
    yield put({type: actionTypes.ERROR})
  }
}
Copy the code

fork(fn, … args)

Fork, like call, is used to call other functions, but fork is non-blocking. That is, after the yield fork(FN, ARgs) line is executed, the program will immediately execute the next line of code without waiting for the fn function to return the result. Execute the following statement

Usage:

import { fork } from 'redux-saga/effects'

export default function* rootSaga() {// The following four Generator functions are executed at once, Do not block execution yield fork(addItemFlow) Yield fork(removeItemFlow) Yield fork(toggleItemFlow) Yield fork(modifyItem)}Copy the code

select(selector, … args)

The select function instructs middleware to call a selector to getState data from a Store. You can also simply think of it as a redux framework function to getState data from a Store: store.getstate ()

Usage:

export function* toggleItemFlow() {// Select effect to get the list of 'getTodoList' on global statelet tempList = yield select(state => state.getTodoList.list)
}
Copy the code

A concrete example

**index.js **

import React from 'react';
import ReactDOM from 'react-dom';
import {createStore, applyMiddleware} from 'redux'
import createSagaMiddleware from 'redux-saga'

import rootSaga from './sagas'
import Counter from './Counter'
import rootReducer from './reducers'Const sagaMiddleware = createSagaMiddleware() // Creates a saga middleware instance // This statement creates a store in the same way as the two lines below // const store = createStore(reducers,applyMiddlecare(middlewares)) const createStoreWithMiddleware = applyMiddleware(middlewares)(createStore) const store = createStoreWithMiddleware(rootReducer) sagaMiddleware.run(rootSaga) const action =type => store.dispatch({ type })

function render() {
  ReactDOM.render(
    <Counter
      value={store.getState()}
      onIncrement={() => action('INCREMENT')}
      onDecrement={() => action('DECREMENT')}
      onIncrementAsync={() => action('INCREMENT_ASYNC')} />,
    document.getElementById('root')
  )
}

render()

store.subscribe(render)
Copy the code

sagas.js

import { put, call, take,fork } from 'redux-saga/effects';
import { takeEvery, takeLatest } from 'redux-saga'

export const delay = ms => new Promise(resolve => setTimeout(resolve, ms));

function* incrementAsync() {yield call(delay, 1000); yield put({type: 'INCREMENT' });
}

export default function* rootSaga() {
  // while(true){
  //   yield take('INCREMENT_ASYNC'); // yield fork(incrementAsync); Yield * takeEvery();"INCREMENT_ASYNC", incrementAsync)
}
Copy the code

reducer.js

export default function counter(state = 0, action) {
  switch (action.type) {
    case 'INCREMENT':
      return state + 1
    case 'DECREMENT':
      return state - 1
    case 'INCREMENT_ASYNC':
      return state
    default:
      return state
  }
}
Copy the code

As can be seen from the above code structure, the way of using Redux-Saga is relatively simple. Compared with the previous CounterApp of Redux framework, there is an additional Sagas file and reducers file is still used in the previous way

Redux-saga redux-saga

  1. Use the createSagaMiddleware method to create the Middleware for Saga, and when creating redux’s store, Use the applyMiddleware function to bind a saga Middleware instance to a store, and you can call the Saga Middleware run function to execute one or more Middleware instances.
  2. In The Middleware of Saga, you can use apis such as takeEvery or takeLatest to listen for an action. When an action is triggered, Saga can use call to initiate an asynchronous action. When the operation is complete, use the put function to trigger the action and update the state synchronously, thus completing the update of the entire state.

Redux, React-Redux, redux-Saga, Redux-Saga, Redux-Saga, Redux-Saga, Redux-Saga, Redux-Saga, Redux-Saga, Redux-Saga, Redux-Saga, Redux-Saga, Redux-Saga, Redux-Saga, Redux-Saga

I hope you can praise, pay attention to and encourage me. I hope you can correct my shortcomings