React15 - redux-saga 中 take的作用详解
在 redux-saga 中,take 是一个非常重要的 Effect 创建函数,它的核心作用是:阻塞性地等待一个指定的 Redux Action 被发起。
具体作用
- 阻塞执行:当 Saga 中执行到
yield take(actionType)这一行时,Saga 会暂停在此处,不再往下执行。 - 等待动作:它会一直等待,直到 Redux 仓库中 dispatch 了一个类型与之匹配的 Action。
- 获取负载:当匹配的 Action 被 dispatch 后,
take会“醒来”,并将整个 Action 对象作为返回值赋给下一步的变量,然后 Saga 继续往下执行。
常见用法示例
1. 基础用法:获取用户信息
import { take, call } from 'redux-saga/effects';
import { fetchUserApi } from './api';
function* watchUserRequest() {
// 1. 阻塞等待,直到有人发起 'FETCH_USER' 这个 Action
const action = yield take('FETCH_USER');
// 2. 当收到 Action 后,从 action.payload 中获取用户ID
const userId = action.payload;
// 3. 调用 API 获取数据
const user = yield call(fetchUserApi, userId);
// ... 后续可以 put 另一个 Action 来将数据存入 Store
}
2. 配合 while 循环:监听每一次动作
take 默认只监听 一次。如果你希望每次用户点击按钮(发起 Action)都执行操作,通常需要把它放在一个无限循环里:
import { take, put } from 'redux-saga/effects';
function* incrementSaga() {
// 每当用户点击 '+' 按钮时,都会 dispatch { type: 'INCREMENT_ASYNC' }
while (true) {
// 每次循环都会阻塞在这里,等待下一次点击
yield take('INCREMENT_ASYNC');
// 收到后,立即发起真正的增加数值的 Action
yield put({ type: 'INCREMENT' });
// 循环结束,再次回到 while 开头,重新执行 take,等待下一次点击
}
}
与 takeEvery 的区别
初学者容易混淆 take 和 takeEvery:
takeEvery:是一个高级辅助函数。它本质上是在底层帮你创建了一个while循环,每次匹配到 Action 时派生(fork)一个新的子任务去处理,它本身不会阻塞后续代码的执行。它允许多个相同类型的任务同时并发运行。take:是一个底层的 Effect。它是阻塞性的,且默认只响应一次。通常用于需要精确控制执行流程的场景,比如实现“先执行 A,再执行 B”的严格顺序逻辑,或者实现“登录-注销”这类有明确状态转换的流程。
举个例子:实现“先登录,后注销”的逻辑
function* loginFlow() {
while (true) {
// 1. 阻塞等待用户登录
yield take('LOGIN');
// ... 执行登录逻辑 ...
// 2. 阻塞等待用户注销。在用户注销之前,不会响应下一次登录
yield take('LOGOUT');
// ... 执行注销逻辑 ...
// 3. 循环,等待下一次登录
}
}
在这个例子中,take 确保了用户必须先注销,才能再次执行登录流程。如果用 takeEvery 则无法实现这种严格的顺序控制。

浙公网安备 33010602011771号