资讯专栏INFORMATION COLUMN

React 实践项目 (三) Redux-Saga

ranwu / 2058人阅读

摘要:在上已经有接近的数了,是目前最热门的前端框架。并且这个任务是最后被启动的那个。如果之前已经有一个任务在执行,那之前的这个任务会自动被取消。如果我们允许多个实例同时启动。或者直到被了,如果是这种情况,将在中抛出一个错误。完整项目代码地址

React在Github上已经有接近70000的 star 数了,是目前最热门的前端框架。而我学习React也有一段时间了,现在就开始用 React+Redux 进行实战!

上回说到使用Redux进行状态管理,这次我们使用Redux-saga 管理 Redux 应用异步操作

React 实践项目 (一)
React 实践项目 (二)
React 实践项目 (三)

- 首先我们来看看登陆的 Reducer
export const auth = (state = initialState, action = {}) => {
  switch (action.type) {
    case LOGIN_USER:
      return state.merge({
        "user": action.data,
        "error": null,
        "token": null,
      });
    case LOGIN_USER_SUCCESS:
      return state.merge({
        "token": action.data,
        "error": null
      });
    case LOGIN_USER_FAILURE:
      return state.merge({
        "token": null,
        "error": action.data
      });
    default:
      return state
  }
};

Sagas 监听发起的 action,然后决定基于这个 action 来做什么:是发起一个异步调用(比如一个 Ajax 请求),还是发起其他的 action 到 Store,甚至是调用其他的 Sagas。

具体到这个登陆功能就是我们在登陆弹窗点击登陆时会发出一个 LOGIN_USER action,Sagas 监听到 LOGIN_USER action,发起一个 Ajax 请求到后台,根据结果决定发起 LOGIN_USER_SUCCESS action 还是LOGIN_USER_FAILURE action

接下来,我们来实现这个流程

创建 Saga middleware 连接至 Redux store

在 package.json 中添加 redux-saga 依赖

"redux-saga": "^0.15.4"

修改 src/redux/store/store.js

/**
 * Created by Yuicon on 2017/6/27.
 */
import {createStore, applyMiddleware } from "redux";
import createSagaMiddleware from "redux-saga"
import reducer from "../reducer/reducer";

import rootSaga from "../sagas/sagas";

const sagaMiddleware = createSagaMiddleware();

const store = createStore(
  reducer,
  applyMiddleware(sagaMiddleware)
);

sagaMiddleware.run(rootSaga);

export default store;

Redux-saga 使用 Generator 函数实现

监听 action

创建 src/redux/sagas/sagas.js

/**
 * Created by Yuicon on 2017/6/28.
 */
import { takeLatest } from "redux-saga/effects";
import {registerUserAsync, loginUserAsync} from "./users";
import {REGISTER_USER, LOGIN_USER} from "../action/users";

export default function* rootSaga() {
  yield [
    takeLatest(REGISTER_USER, registerUserAsync),
    takeLatest(LOGIN_USER, loginUserAsync)
  ];
}

我们可以看到在 rootSaga 中监听了两个 action 登陆和注册 。

在上面的例子中,takeLatest 只允许执行一个 loginUserAsync 任务。并且这个任务是最后被启动的那个。 如果之前已经有一个任务在执行,那之前的这个任务会自动被取消。

如果我们允许多个 loginUserAsync 实例同时启动。在某个特定时刻,我们可以启动一个新 loginUserAsync 任务, 尽管之前还有一个或多个 loginUserAsync 尚未结束。我们可以使用 takeEvery 辅助函数。

发起一个 Ajax 请求

获取 Store state 上的数据

selectors.js

/**
 * Created by Yuicon on 2017/6/28.
 */
export const getAuth = state => state.auth;

api

api.js

/**
 * Created by Yuicon on 2017/7/4.
 * https://github.com/Yuicon
 */

/**
 * 这是我自己的后台服务器,用 Java 实现
 * 项目地址:https://github.com/DigAg/digag-server
 * 文档:http://139.224.135.86:8080/swagger-ui.html#/
 */
const getURL = (url) => `http://139.224.135.86:8080/${url}`;

export const login = (user) => {
  return fetch(getURL("auth/login"), {
    method: "POST",
    headers: {
      "Content-Type": "application/json"
    },
    body: JSON.stringify(user)
  }).then(response => response.json())
    .then(json => {
      return json;
    })
    .catch(ex => console.log("parsing failed", ex));
};

创建 src/redux/sagas/users.js

/**
 * Created by Yuicon on 2017/6/30.
 */
import {select, put, call} from "redux-saga/effects";
import {getAuth, getUsers} from "./selectors";
import {loginSuccessAction, loginFailureAction, registerSuccessAction, registerFailureAction} from "../action/users";
import {login, register} from "./api";
import "whatwg-fetch";

export function* loginUserAsync() {
  // 获取Store state 上的数据
  const auth = yield select(getAuth);
  const user = auth.get("user");
  // 发起 ajax 请求
  const json = yield call(login.bind(this, user), "login");
  if (json.success) {
    localStorage.setItem("token", json.data);
    // 发起 loginSuccessAction
    yield put(loginSuccessAction(json.data));
  } else {
    // 发起 loginFailureAction
    yield put(loginFailureAction(json.error));
  }
}

select(selector, ...args) 用于获取Store state 上的数据
put(action) 发起一个 action 到 Store
call(fn, ...args) 调用 fn 函数并以 args 为参数,如果结果是一个 Promise,middleware 会暂停直到这个 Promise 被 resolve,resolve 后 Generator 会继续执行。 或者直到 Promise 被 reject 了,如果是这种情况,将在 Generator 中抛出一个错误。

Redux-saga 详细api文档

结语

我在工作时用的是 Redux-Thunk, Redux-Thunk 相对来说更容易实现和维护。但是对于复杂的操作,尤其是面对复杂异步操作时,Redux-saga 更有优势。到此我们完成了一个 Redux-saga 的入门教程,Redux-saga 还有很多奇妙的地方,大家可以自行探索。

完整项目代码地址

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/88321.html

相关文章

  • React 实践项目 (二) redux + immutable + redux-saga

    摘要:在上已经有接近的数了,是目前最热门的前端框架。惟一改变的办法是触发,一个描述发生什么的对象。对对象的任何修改或添加删除操作都会返回一个新的对象。从导入需要的类型初始化状态就是一个纯函数,接收旧的和,返回新的。 React在Github上已经有接近70000的 star 数了,是目前最热门的前端框架。而我学习React也有一段时间了,现在就开始用 React+Redux 进行实战! Re...

    amuqiao 评论0 收藏0
  • React 实践项目 (四)

    摘要:在上已经有接近的数了,是目前最热门的前端框架。为了检验效果当然是选择部署到服务器。下篇文章将会介绍利用的镜像部署应用。完整项目代码地址 React在Github上已经有接近70000的 star 数了,是目前最热门的前端框架。而我学习React也有一段时间了,现在就开始用 React+Redux 进行实战! 上回说到使用Redux-saga 管理 Redux 应用异步操作,应用还是只有...

    AaronYuan 评论0 收藏0
  • React生态,dva源码阅读

    摘要:下面会从浅到深,淡淡在阅读源码过程中自己的理解。分拆子页面后,每一个子页面对应一个文件。总结上面就是最早版本的源码,很简洁的使用了等其目的也很简单简化相关生态的繁琐逻辑参考源码地址   dva的思想还是很不错的,大大提升了开发效率,dva集成了Redux以及Redux的中间件Redux-saga,以及React-router等等。得益于Redux的状态管理,以及Redux-saga中...

    bergwhite 评论0 收藏0
  • React生态,dva源码阅读

    摘要:下面会从浅到深,淡淡在阅读源码过程中自己的理解。分拆子页面后,每一个子页面对应一个文件。总结上面就是最早版本的源码,很简洁的使用了等其目的也很简单简化相关生态的繁琐逻辑参考源码地址   dva的思想还是很不错的,大大提升了开发效率,dva集成了Redux以及Redux的中间件Redux-saga,以及React-router等等。得益于Redux的状态管理,以及Redux-saga中...

    txgcwm 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<