React状态管理——redux-saga异步操作

发布于:2025-06-19 ⋅ 阅读:(8) ⋅ 点赞:(0)

目录

一、基础知识

1.1 生成器函数Generator

1.2 可执行生成器

二、redux-saga

2.1 核心概念

2.1.1 Saga

2.1.2 Effect

2.1.3 工作原理

2.2 基本使用

2.2.1 安装

2.2.2 目录结构(以多saga、多reducer为例)

2.2.3 配置

2.2.3.1 配置reducer

2.2.3.2 配置saga

2.2.3.3 配置store

2.2.4 示例

2.2.4.1 测试代码

2.2.4.2 运行结果

一、基础知识

1.1 生成器函数Generator

// 前面加*才会成为生成器函数
function* test() {
  console.log(1111);
  var input1 = yield "1111暂停"; // 调用gen.next()会将yield的结果 传给res1
  console.log(2222, input1); //通过gen.next(bbbb)进行传参,可以得到结果,为什么不是aaaa,因为第一次console.log(1111);执行后就停止
  yield "2222暂停";
  console.log(3333);
  yield "3333暂停";
}

let gen = test();

let res1 = gen.next("aaaa"); //调用next方法,遇到yield就停止
let res2 = gen.next("bbbb");
let res3 = gen.next("cccc");
let res4 = gen.next(); // 后面没东西了

console.log(res1); //返回的是个对象{value:...,done:...}
console.log(res2);
console.log(res3);
console.log(res4); // done:true,表示生成器执行完毕

1.2 可执行生成器

function getData1() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(["data1"]);
    }, 1000);
  });
}

function getData2(data) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve([...data, "data2"]);
    }, 1000);
  });
}

function getData3(data) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve([...data, "data3"]);
    }, 1000);
  });
}

function* gen() {
  let f1 = yield getData1();
  console.log(f1);
  let f2 = yield getData2(f1);
  console.log(f2);
  let f3 = yield getData3(f2);
  console.log(f3);
}

function run(fn) {
  let g = fn();

  function next(data) {
    let result = g.next(data);
    if (result.done) {
      return result.value;
    }
    result.value.then((res) => {
      next(res);
    });
  }

  next();
}

run(gen);

二、redux-saga

2.1 核心概念

Redux-Saga 是一个用于管理 Redux 应用异步操作(副作用)的中间件库。它使用 ES6 的 Generator 函数让异步流程更易读、更易测试。

在saga中,全局监听器和接收器使用Generator函数和saga自身的一些辅助函数实现对整个流程的管控

2.1.1 Saga

Saga 是一个 Generator 函数,它使用 yield 关键字来暂停和恢复执行。Saga 负责组织和控制应用的副作用(如数据获取、缓存访问等)。

2.1.2 Effect

Effect 是一个纯 JavaScript 对象,包含了一些将被 saga 中间件执行的指令。常见的 Effect 创建器包括:

  • take: 等待指定的 action

  • put: 发起一个 action

  • call: 调用一个函数(通常是异步的)

  • fork: 非阻塞地执行一个任务

  • all: 并行运行多个 Effect

2.1.3 工作原理

Redux-Saga 作为中间件运行在 Redux 应用中:

  1. 监听特定的 Redux action

  2. 执行相应的副作用逻辑

  3. 可能派发新的 action 来更新 store

2.2 基本使用

2.2.1 安装

npm redux redux-saga

2.2.2 目录结构(以多saga、多reducer为例)

        在目录结构中,reducer与传统redux配置一致,store/index.js在传统配置中添加了saga,store/saga文件夹下的saga1是基础示例,saga2是应用了链式调用(与 async await相似)

2.2.3 配置

2.2.3.1 配置reducer

目录:store/reducer文件夹

step1:创建reducer

// store/reducer/reducer1

const initState = {
  list1: [],
};

function reducer(prevState = initState, action) {
  let newState = { ...prevState };
  switch (action.type) {
    case "change-list1":
      newState.list1 = action.payload;
      return newState;
    default:
      return newState;
  }
}

export default reducer;
// store/reducer/reducer2

const initState = {
  list2: [],
};

function reducer(prevState = initState, action) {
  let newState = { ...prevState };
  switch (action.type) {
    case "change-list2":
      newState.list2 = action.payload;
      return newState;
    default:
      return newState;
  }
}

export default reducer;

step2:结合多个reducer

// store/reducer/index.js

import { combineReducers } from "redux";
import reducer1 from "./reducer1";
import reducer2 from "./reducer2";

export default combineReducers({
  r1: reducer1, // 前面的名字随便取,只要store.getState().r1对应
  r2: reducer2,
});
2.2.3.2 配置saga

目录:store/saga文件夹

step1:创建saga

// store/saga/saga1.js

import { call, put } from "redux-saga/effects";

function* getList1() {
  // 异步处理
  // call函数发送异步请求 call的传参是个Promise对象
  let res = yield call(getListAction1);
  // put函数发出新的action
  yield put({ type: "change-list1", payload: res });
}

function getListAction1() {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(["111", "222", "333"]);
    }, 100);
  });
}

export { getList1 };
// store/saga/saga2.js

import { call, put } from "redux-saga/effects";

function* getList2() {
  // 异步处理
  // call函数发送异步请求 call的传参是个Promise对象
  let res1 = yield call(getListAction2_1); // 阻塞调用
  let res2 = yield call(getListAction2_2, res1); // 第二个参数会将结果传参给getListAction2_2
  // put函数发出新的action
  yield put({ type: "change-list2", payload: res2 });
}

function getListAction2_1() {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(["444", "555", "666"]);
    }, 1000);
  });
}

function getListAction2_2(data) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve([...data, "777", "888", "999"]);
    }, 1000);
  });
}

export { getList2 };

step2:监听多个saga

// store/saga/index.js

import { takeEvery } from "redux-saga/effects";
import { getList1 } from "./saga1";
import { getList2 } from "./saga2";

function* watchSaga() {
  console.log(111);
  yield takeEvery("get-list1", getList1);
  yield takeEvery("get-list2", getList2);
}

export default watchSaga;
2.2.3.3 配置store
// store/index.js

import { createStore, applyMiddleware } from "redux";
import reducer from "./reducer";
import createSagaMidlleWare from "redux-saga";
import watchSaga from "./saga/index";
const sagaMiddleWare = createSagaMidlleWare();
const store = createStore(reducer, applyMiddleware(sagaMiddleWare));

sagaMiddleWare.run(watchSaga); // 运行saga任务
export default store;

2.2.4 示例

2.2.4.1 测试代码
import React from "react";
import store from "./store";
// import "./02-可执行生成器";
export default function App() {
  const fetchClick1 = () => {
    if (store.getState().r1.list1.length === 0) {
      //dispatch
      store.dispatch({ type: "get-list1" });
    } else {
      console.log("缓存1111", store.getState().r1.list1);
    }
  };

  const fetchClick2 = () => {
    if (store.getState().r2.list2.length === 0) {
      //dispatch
      store.dispatch({ type: "get-list2" });
    } else {
      console.log("缓存2222", store.getState().r2.list2);
    }
  };

  return (
    <div>
      <button onClick={fetchClick1}>click-ajax-异步缓存1111</button>
      <button onClick={fetchClick2}>click-ajax-异步缓存2222</button>
    </div>
  );
}
2.2.4.2 运行结果

对按钮进行点击,第1次点击为异步请求,第2次点击为缓存


网站公告

今日签到

点亮在社区的每一天
去签到