初学者教程
本教程的目标
本教程试图以一种(希望)易于理解的方式介绍redux-saga。
在我们的入门教程中,我们将使用Redux仓库中的简单Counter演示。这个应用程序非常基础,但很适合阐述redux-saga的基本概念,而不会迷失在过多的细节中。
初始设置
在我们开始之前,克隆教程仓库。
本教程的最终代码位于
sagas分支。
然后在命令行中运行:
$ cd redux-saga-beginner-tutorial
$ npm install
要启动应用程序,运行:
$ npm start
编译完成后,用浏览器打开http://localhost:9966。
我们从最基本的用例开始:2个按钮Increment和Decrement用于计数器。稍后,我们将引入异步调用。
如果一切顺利,你应该看到2个按钮Increment和Decrement,以及下面显示Counter: 0的消息。
如果你在运行应用程序时遇到问题,欢迎在教程仓库创建问题。
Hello Sagas!
我们将创建我们的第一个Saga。按照传统,我们将为Sagas编写我们的'Hello, world'版本。
创建一个sagas.js文件,然后添加以下代码片段:
export function* helloSaga() {
  console.log('Hello Sagas!')
}
所以没有什么可怕的,只是一个普通的函数(除了*)。它所做的只是在控制台打印一个问候消息。
为了运行我们的Saga,我们需要:
- 创建一个带有要运行的Sagas列表的Saga中间件(到目前为止,我们只有一个
helloSaga) - 将Saga中间件连接到Redux store
 
我们将对main.js进行更改:
// ...
import { createStore, applyMiddleware } from 'redux'
import createSagaMiddleware from 'redux-saga'
// ...
import { helloSaga } from './sagas'
const sagaMiddleware = createSagaMiddleware()
const store = createStore(
  reducer,
  applyMiddleware(sagaMiddleware)
)
sagaMiddleware.run(helloSaga)
const action = type => store.dispatch({type})
// 其余部分不变
首先,我们从./sagas模块导入我们的Saga。然后我们使用redux-saga库导出的工厂函数createSagaMiddleware创建一个中间件。
在运行我们的helloSaga之前,我们必须使用applyMiddleware将我们的中间件连接到Store。然后我们可以使用sagaMiddleware.run(helloSaga)来启动我们的Saga。
到目前为止,我们的Saga没有做什么特别的事情。它只是记录一条消息然后退出。
进行异步调用
现在让我们添加一些更接近原始 Counter 示例的内容。为了说明异步调用,我们将添加另一个按钮,在点击后一秒钟增加计数器。
首先,我们将为 UI 组件提供一个额外的按钮和一个回调 onIncrementAsync。
我们将对 Counter.js 进行更改:
const Counter = ({ value, onIncrement, onDecrement, onIncrementAsync }) =>
  <div>
    <button onClick={onIncrementAsync}>
      一秒后增加
    </button>
    {' '}
    <button onClick={onIncrement}>
      增加
    </button>
    {' '}
    <button onClick={onDecrement}>
      减少
    </button>
    <hr />
    <div>
      点击了: {value} 次
    </div>
  </div>
接下来,我们应该将组件的 onIncrementAsync 连接到 Store 操作。
我们将如下修改 main.js 模块
function render() {
  ReactDOM.render(
    <Counter
      value={store.getState()}
      onIncrement={() => action('INCREMENT')}
      onDecrement={() => action('DECREMENT')}
      onIncrementAsync={() => action('INCREMENT_ASYNC')} />,
    document.getElementById('root')
  )
}
注意,与 redux-thunk 不同,我们的组件分派一个普通对象操作。
现在我们将引入另一个 Saga 来执行异步调用。我们的用例如下:
对于每一个
INCREMENT_ASYNC操作,我们希望启动一个任务,该任务将执行以下操作
- 等待 1 秒,然后增加计数器
 
将以下代码添加 到 sagas.js 模块:
import { put, takeEvery } from 'redux-saga/effects'
const delay = (ms) => new Promise(res => setTimeout(res, ms))
// ...
// 我们的 worker Saga:将执行异步增加任务
export function* incrementAsync() {
  yield delay(1000)
  yield put({ type: 'INCREMENT' })
}
// 我们的 watcher Saga:在每个 INCREMENT_ASYNC 上产生一个新的 incrementAsync 任务
export function* watchIncrementAsync() {
  yield takeEvery('INCREMENT_ASYNC', incrementAsync)
}