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_SUCCESSaction 还是LOGIN_USER_FAILUREaction

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

  • 创建 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://github.com/DigAg/digag-pc-react

React 实践项目 (三)的更多相关文章

  1. React 实践项目 (五)

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

  2. React 实践项目 (二)

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

  3. android 实践项目三

    android 实践项目三 本周我主要完成的任务是将代码进行整合,然后实现百度地图的定位与搜索功能.在这次实现的 图形界面如下: 在本周的工作中主要的实现出来定位与收索的功能,在地图中能实现了定位,显 ...

  4. React 实践项目 (一)

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

  5. python实践项目三:将列表添加到字典

    1.创建一个字典,其中键是字符串,描述一个物品,值是一个整型值,说明有多少该物品.例如,字典值{'rope': 1, 'torch': 6, 'gold coin': 42, 'dagger': 1, ...

  6. 总结 React 组件的三种写法 及最佳实践 [涨经验]

    React 专注于 view 层,组件化则是 React 的基础,也是其核心理念之一,一个完整的应用将由一个个独立的组件拼装而成. 截至目前 React 已经更新到 v15.4.2,由于 ES6 的普 ...

  7. Immutable.js 以及在 react+redux 项目中的实践

    来自一位美团大牛的分享,相信可以帮助到你. 原文链接:https://juejin.im/post/5948985ea0bb9f006bed7472?utm_source=tuicool&ut ...

  8. 总结 React 组件的三种写法 及最佳实践

    React 专注于 view 层,组件化则是 React 的基础,也是其核心理念之一,一个完整的应用将由一个个独立的组件拼装而成. 截至目前 React 已经更新到 v15.4.2,由于 ES6 的普 ...

  9. Expo大作战(三)--针对已经开发过react native项目开发人员有针对性的介绍了expo,expo的局限性,开发时项目选型注意点等

    简要:本系列文章讲会对expo进行全面的介绍,本人从2017年6月份接触expo以来,对expo的研究断断续续,一路走来将近10个月,废话不多说,接下来你看到内容,讲全部来与官网 我猜去全部机翻+个人 ...

随机推荐

  1. BAYESIAN STATISTICS AND CLINICAL TRIAL CONCLUSIONS: WHY THE OPTIMSE STUDY SHOULD BE CONSIDERED POSITIVE(转)

    Statistical approaches to randomised controlled trial analysis The statistical approach used in the ...

  2. 如何有效的跟踪线上 MySQL 实例表和权限的变更

    介绍 从系统管理员或 DBA 的角度来讲, 总期望将线上的各种变更限制在一个可控的范围内, 减少一些不确定的因素. 这样做有几点好处: . 记录线上的库表变更; . 对线上的库表变更有全局的了解; . ...

  3. TCP:三次握手、四次握手、backlog及其他

    TCP是什么 首先看一下OSI七层模型: 然后数据从应用层发下来,会在每一层都加上头部信息进行封装,然后再发送到数据接收端,这个基本的流程中每个数据都会经过数据的封装和解封的过程,流程如下图所示: 在 ...

  4. hdu_A Walk Through the Forest ——迪杰特斯拉+dfs

    A Walk Through the Forest Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 65536/32768K (Java/ ...

  5. poj1379

    poj1379 题意 给出 n 个洞的坐标,要求找到一点使得这一点距离最近洞的距离最远. 分析 通过这道题学习一下模拟退火算法, 这种随机化的算法,在求解距离且精度要求较小时很有用. 简而言之,由随机 ...

  6. jquery 根据数据库值设置radio的选中

    jsp代码: <label>性 别</label> <input type="radio" value="1" name=&quo ...

  7. 两个同级div等高布局

    显示效果: css代码如下 .wrap{ overflow:hidden; } .left{ width:30%; background:#09C; } .right{ width:70%; back ...

  8. 提高java编程质量 - (三)三目运算符的两个操作数类型尽量一致

    先看一个例子: package com.test; public class TernaryOperator { public static void main(String[] args) { in ...

  9. Scrapy中使用cookie免于验证登录和模拟登录

    Scrapy中使用cookie免于验证登录和模拟登录 引言 python爬虫我认为最困难的问题一个是ip代理,另外一个就是模拟登录了,更操蛋的就是模拟登录了之后还有验证码,真的是不让人省心,不过既然有 ...

  10. 关于MATLAB处理大数据坐标文件2017622

    今天新提交了一次数据,总量达到10337个,本以为成绩会突飞猛进,没想到还是不如从前 但是已经找到人工鼠标轨迹的程序,有待完善,接下来兵分四路:找特征.决策树.完善人工轨迹程序,使其可以将生成的数据自 ...