react integrates native redux

Keywords: Javascript React axios

react integrates native redux(3)

Preface

stay react integrates native redux(1) Based on this, redux-saga can extend reducer, which is different from redux-saga. redux-thunk saga divides redux into two parts, one is synchronous updating data, the other is asynchronous operation, the other is pure preservation, the other is logical preservation, while thunk only extends action to make action logical, both of which aim to reduce code coupling

Project creation

Reference resources react integrates native redux(1)

Increase dependency packages

yarn add redux-saga -s

src file directory

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

Add effects.js file

store.js Extension Adjustment

redux-saga middleware is mainly introduced and used. The basic steps are as follows

  1. Saga introduces import createSaga from "redux-saga"
  2. Saga initializes const saga = createSaga()
  3. Saga uses createStore (reducer, composeWithDevTools (apply Middleware (saga)) as middleware
  4. Saga runs saga.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();

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

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

effects.js Additional Writing

Looking at the code, the key parts are annotated.

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

const fetchListEffect = function*(action) {
  const { payload } = action;
  // Asynchronous operations can directly call functions that return promise s, such as fetch.axios, etc. Officially recommended encapsulation with call, see updateListApi specifically.
  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 }); // Here put 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(updateListApi, payload); // The official recommendation for asynchronous data operations is to call parameter 1 as a function returning promise and parameter 2 as a transfer parameter.
  yield put({ type: "SAVE", payload: data });
};

// saga calls generator functions
export default function*() {
  // takeEvery parameter 1 is an action type name 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 in the hook function, similar to this.setState(store.getState())
  const [state, setState] = useState(store.getState());
  useEffect(() => {
    // Store subscription function, which is automatically executed when the state changes through store.dispatch distribution action
    store.subscribe(() => {
      setState(store.getState()); //Reset the value of component state to update the view
    });
  }, []); // [] Represents only one execution

  const { list } = state;

  const addList = () => {
    list.push(Date.now());
    store.dispatch({ type: "SAVE", payload: { list } }); //Distributing an action object
  };

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

  return (
    <div>
      <button onClick={addList}>add</button>
      {/* Click Event Definition, saga Mode */}
      <button onClick={() => store.dispatch({ type: "update/list" })}>
        update
      </button>
      <ul>
        {list.map(v => {
          return <li key={v}>{v}</li>;
        })}
      </ul>
    </div>
  );
};
Above is the complete construction and use of redux+redux-saga. Complete code

If you find it too cumbersome, there is a good framework for integrating saga, such as dva.js,umi.js It's ready to use.

Posted by Brian W on Thu, 10 Oct 2019 12:36:11 -0700