React integrates native Redux (3)

Time:2020-1-14

React integrates native Redux (3)

Preface

Based on the fact that react integrates the native Redux (1), plus the Redux saga, it can extend the reducer. Unlike the Redux thunk, Saga divides the Redux into two parts, one is synchronous data updating, the other is asynchronous operation, in other words, one is pure saving, the other is saving with logic, while thunk only extends the action, making the action logical, Both aim to reduce code coupling

Project creation

Integrating native Redux with react (1)

Add dependency package

yarn add redux-saga -s

SRC file directory

|-app.js
|-store.js
|-index.js
|-effects.js

New effects.js file

Store.js extension adjustment

It mainly introduces Redux saga middleware and uses it. The basic steps are as follows

  1. Introduction of Sagaimport createSaga from "redux-saga"
  2. Saga initializationconst saga = createSaga()
  3. Saga as middlewarecreateStore(reducer, composeWithDevTools(applyMiddleware(saga)))
  4. Saga operationsaga.run(effect)

Specific code

// store.js
import { createStore, applyMiddleware } from "redux";
import createSaga from "redux-saga";
Import {composewithdevtools} from "Redux devtools extension"; // Chrome Redux debugging tool
import effect from "./effects";

//State initial value
const initState = {
  list: ["a", "b"]
};

//Reducer format
const reducer = (state = initState, action) => {
  const { type, payload } = action;
  //Type processing of action
  if (type === "SAVE") {
    return Object.assign({}, state, payload);
  }
  return state;
};

const saga = createSaga();

/**
 *Instantiate store
 *Parameter 1: Reducer
 *Parameter 2: Middleware
 */
export default createStore(reducer, composeWithDevTools(applyMiddleware(saga)));

//Running saga, the argument is a generator function
saga.run(effect);

Effects.js add writing

See the code for details. There are notes for key parts

// actions.js
import { call, put, takeEvery } from "redux-saga/effects";

const fetchListEffect = function*(action) {
  const { payload } = action;
  //Asynchronous operation can directly call the function that returns promise, such as fetch.axios. It is officially recommended to encapsulate it with call. For details, see updatelitapi
  const { data } = yield new Promise(resolve => {
    setTimeout(() => {
      const data = {
        code: 0,
        msg: "ok",
        data: {
          list: ["hello", "saga"],
          payload
        }
      };
      resolve(data);
    }, 2000);
  });
  Yield put ({type: "save", payload: Data}); // put here is the encapsulation of store.dispatch
};

/**
 *This function can be split into service files to further reduce coupling
 *@ param {parameter} payload
 */
const updateListApi = payload => {
  return new Promise(resolve => {
    setTimeout(() => {
      const data = {
        code: 0,
        msg: "ok",
        data: {
          list: ["hello", "saga", "update"],
          payload
        }
      };
      resolve(data);
    }, 1000);
  });
};

const updateListEffect = function*(action) {
  const { payload } = action;
  Const {data} = yield call (updatelitapi, payload); // for asynchronous data operations, it is officially recommended that call function call parameter 1 is the function that returns promise, and parameter 2 is the pass parameter
  yield put({ type: "SAVE", payload: data });
};

//Generator function called by Saga
export default function*() {
  //Takeevery parameter 1 is the type name of action parameter 2 is a generator function
  yield takeEvery("fetch/list", fetchListEffect);

  yield takeEvery("update/list", updateListEffect);
}

Use, app.js rewrite

Main operation

useEffect(() => {
  store.dispatch({ type: "fetch/list", payload: { id: 1 } });
}, []);
onClick={() => store.dispatch({ type: "update/list" })}

Complete code

// app.js
import React, { useState, useEffect } from "react";
import store from "./store";

export default () => {
  //Get the state in the store and put it into the hook function, similar to this. Setstate (store. Getstate())
  const [state, setState] = useState(store.getState());
  useEffect(() => {
    //Store subscription function, which is automatically executed when state changes through store.dispatch distribution action
    store.subscribe(() => {
      SetState (store.getState ()); // reset the value of component state to update the view
    });
  }, []; / [] means only one execution

  const { list } = state;

  const addList = () => {
    list.push(Date.now());
    Store. Dispatch ({type: 'Save', payload: {list}}); // distribute an action object
  };

  //Initialize request data saga mode
  useEffect(() => {
    store.dispatch({ type: "fetch/list", payload: { id: 1 } });
  }, []);

  return (
    <div>
      <button onClick={addList}>add</button>
      {/ * click event definition, Saga pattern * /}
      <button onClick={() => store.dispatch({ type: "update/list" })}>
        update
      </button>
      <ul>
        {list.map(v => {
          return <li key={v}>{v}</li>;
        })}
      </ul>
    </div>
  );
};
The above isredux+redux-sagaComplete construction and use of, check the complete code

If you think it’s too troublesome, you can integrate saga framework, such as dva.js and umi.js, and use them as you go