专栏首页full stack developmentRedux:从action到saga

Redux:从action到saga

前端应用消失的部分

一个现代的、使用了redux的前端应用架构可以这样描述:

  1. 一个存储了应用不可变状态(state)的store
  2. 状态(state)可以被绘制在组件里(html或者其他的东西)。这个绘制方法通常是简单而且可测试的(并不总是如此)纯方法。
const render = (state) => components
  1. 组件可以给store分发action
  2. 使用reducer这种纯方法来根据就的状态返回新的状态
const reducer = (oldState, action) => newState
  1. 从一再来一次这看起来容易理解。但是当需要处理异步的action(在函数式编程里称为副作用)的时候事情就没有这么简单了。为了解决这个问题,redux建议使用中间件(尤其是thunk)。基本上,如果你需要出发副作用(side effects),使用一种特定的action生成方法:一种返回一个方法的方法,可以实现任意的异步访问并分发任意你想要的action。使用这个方式会很快导致action生成方法变得复杂并难以测试。这个时候就需要redux-saga了。在redux-saga里saga就是一个可声明的组织良好的副作用实现方式(超时,API调用等等。。)所以不用再用redux-thunk中间件来写,我们用saga来发出action并yield副作用。这样不复杂?action creator这样的写法不是更简单?虽然看起来是这样的,但是NO!我们来看看如何写一个action creator来获取后端数据并分发到redux store。function loadTodos() { return dispatch => { dispatch({ type: 'FETCH_TOTOS' }); fetch('/todos').then(todos => { dispatch({ type: 'FETCH_TODOS', payload: todos }); }); } }这是最简单的thunk action creator了,并且如你所见,唯一测试这个代码的方法是模拟获取数据的方法。我们来看看用saga代替action creator获取todo数据的方法:import { call, put } from 'redux-saga'; function* loadTodos() { yield put({ type: 'FETCH_TODOS' }); const todos = yield call(fetch, '/todos'); yield put({ type: 'FETCH_TODOS', payload: todos }); }正如你所见一个saga就是一个生成副作用(side effects)的generator。我(作者)更加倾向于把整个generator叫做纯generator,因为它不会实际执行副作用,只会生成一个要执行的副作用的描述。在上面的例子中我用了两种副作用:
  2. 一个put副作用,它会给redux store分发一个action。
  3. 一个call副作用,它会执行一个异步的方法(promise,cps后者其他的saga)。

现在,测试这个saga就非常的容易了:

import { call, put } from 'redux-saga';

const mySaga = loadTodos();
const myTodos = [{ message: 'text', done: false }];
mySaga.next();
expect(mySaga.next().value).toEqual(put({ type: 'FETCH_TOTOS' }));
expect(mySaga.next().value).toEqual(call(fetch, '/todos'));
expect(mySaga.next().value).toEqual(put({ type: 'FETCH_TODOS', payload: myTodos }));

触发一个saga

thunk的action creator在分发它返回的方法的时候就会触发。saga不同,它们就像是运行在后台的守护任务(daemon task)一样有自己的运行逻辑(by Yasine Elouafi redux-saga的作者)。

所以,我们来看看如何在redux应用里添加saga。

import { createStore, applyMiddleware } from 'redux';
import sagaMiddleware from 'redux-saga';

const createStoreWithSaga = applyMiddleware(
  sagaMiddleware([loadTodos])
)(createStore);

let store = createStoreWithSaga(reducer, initialState);

绑定saga

一个saga本身就是一个副作用,就如同redux的reducer一样,绑定saga非常简单(但是很好的理解ES6的generator是非常有必要的)。

在之前的例子里,loadTodos saga在一开始就会触发。但是,如果我们想要每次一个action分发到store的时候触发saga要怎么做呢?看代码:

import { fork, take } from 'redux-saga';

function* loadTodos() {
  yield put({ type: 'FETCHING_TODOS' });
  const todos = yield call(fetch, '/todos');
  yield put({ type: 'FETCHED_TODOS', payload: todos });
}

function* watchTodos() {
  while(yield take('FETCH_TODOS')) {
    yield fork(loadTodos);
  }
}

// 我们需要更新saga常量 createStoreWithSaga = applyMiddleware(
  sagaMiddleware([watchTodos])
)(createStore);

上例用到了两个特殊的effect:

  • take effect,它会等待分发redux action的时候执行
  • fork effect, 它会触发另外一个effect,在子effect开始之前就会执行

结语

给前端应用添加redux和redux-saga的流程是这样的:

  1. store持有一个应用的state。
  2. state会被绘制到组件上(html或者其他的什么)。它是一个简单可测试的方法:
const render = (state) => components
  1. 组件会触发修改store的action。
  2. state使用reducer这样的纯方法来修改的。
const reducer = (oldState, action) => newState
  1. 也许某些effect会被一个action或者其他的effect触发。function* saga() { yield effect; }
  2. 从1开始。

原文链接:https://riad.blog/2015/12/28/redux-nowadays-from-actions-creators-to-sagas/

原文链接:https://riad.blog/2015/12/28/redux-nowadays-from-actions-creators-to-sagas/

原文作者:Riad Benguella

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 【腾讯云的1001种玩法】云服务器搭建Python爬虫环境

    在上一篇文章中,我们已经学会了在云服务器上搭建Python环境了,假设你已经在云服务器上搭建好了Python环境,我们将进入下一步:搭建Python爬虫环境。

    钟志远
  • Django数据处理的一些实践

    提到 Django 肯定避不开 MVC 模式,即模型(Model)-视图(View)-控制器(Controller),通过将业务逻辑、数据、界面显示分离的方法组...

    唐郑望
  • 实战干货:从零快速搭建自己的爬虫系统

    本文简要归纳了网页爬虫的基础知识,着重于利用现有组件,快速建立一套实际可用的网页爬取、分析系统。系统主要使用Python 作为开发语言,在 Linux 或 Ma...

    胖兔子兔胖
  • 深度学习入门实战(二):用TensorFlow训练线性回归

    上一篇文章我们介绍了 MxNet 的安装,但 MxNet 有个缺点,那就是文档不太全,用起来可能是要看源代码才能理解某个方法的含义,所以今天我们就介绍一下 Te...

    serena
  • 如何轻松爬取网页数据?

    在实际工作中,难免会遇到从网页爬取数据信息的需求,如:从微软官网上爬取最新发布的系统版本。很明显这是个网页爬虫的工作。本文将根据网站特性进行分类介绍几种使用py...

    腾讯移动品质中心TMQ
  • 反爬虫和抗DDOS攻击技术实践

    企鹅媒体平台媒体名片页反爬虫技术实践,分布式网页爬虫技术、利用人工智能进行人机识别、图像识别码、频率访问控制、利用无头浏览器PhantomJS、Selenium...

    张宁
  • 腾讯云主机Python3环境安装Scrapy爬虫框架过程及常见错误

    Scrapy安装介绍Scrapy的安装有多种方式,它支持Python2.7版本及以上或Python3.3版本及以上。下面说明Python3环境下的安装过程。Sc...

    崔庆才
  • 【腾讯云的1001种玩法】云服务器搭建Python环境

    之前一直在用阿里云服务器跑爬虫、小脚本。这两天在朋友的安利下转到了腾讯云上面来,刚好趁这个机会写一写有关于云服务器上Python爬虫环境的搭建。

    钟志远
  • 深度学习入门实战(一):像Prisma一样算法生成梵高风格画像

    现在人工智能是个大热点,而人工智能离不开机器学习,机器学习中深度学习又是比较热门的方向,本系列文章就从实战出发,介绍下如何使用MXnet进行深度学习~

    serena
  • Python 远程控制模块 paramiko 问题解决记录

    生产环境中使用paramiko作SSH远程控制时,发现会有部分机器报Error reading SSH protocol banner错误,尝试使用ssh命令连...

    张戈

扫码关注云+社区

领取腾讯云代金券