下面给出一条「从零到上线」的完整学习路径,并穿插可运行的最小代码片段,帮助你把 Redux + Redux-Saga 真正用起来。阅读顺序:概念 → 环境 → HelloSaga → 异步流 → 项目实战 → 常见坑。

──────────────────

  1. 概念速记(30 秒) • Redux:单一 Store、纯函数 reducer、同步数据流
    • Redux-Saga:基于 Generator 的「进程级」中间件,专门负责异步副作用(网络、定时器、WebSocket…)
    • 三者关系:
    UI → dispatch(action) → saga 拦截 → 做副作用 → put(action) → reducer → 更新 Store → UI

────────────────── 2. 环境与最小可运行例子 (1)安装

npm i redux react-redux redux-saga

(2)src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import { createStore, applyMiddleware } from 'redux';
import createSagaMiddleware from 'redux-saga';
import { Provider } from 'react-redux';
import App from './App';
import rootReducer from './reducers';
import rootSaga from './sagas';
 
const sagaMiddleware = createSagaMiddleware();
const store = createStore(rootReducer, applyMiddleware(sagaMiddleware));
sagaMiddleware.run(rootSaga);
 
ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);

(3)src/sagas/helloSaga.js(官方「Hello World」)

export function* helloSaga() {
  console.log('Hello Sagas!');
}

(4)src/sagas/index.js(根 Saga)

import { all } from 'redux-saga/effects';
import { helloSaga } from './helloSaga';
 
export default function* rootSaga() {
  yield all([helloSaga()]);
}

运行后控制台即出现 Hello Sagas!

────────────────── 3. 异步流程:1 秒递增计数器 需求:点击按钮 → 等待 1 秒 → 计数 +1
(1)组件派发普通 action

<button onClick={() => dispatch({ type: 'INCREMENT_ASYNC' })}>
  +1 after 1s
</button>

(2)sagas/counterSaga.js

import { delay, put, takeEvery } from 'redux-saga/effects';
 
function* incrementAsync() {
  yield delay(1000);        // 阻塞 1 秒
  yield put({ type: 'INCREMENT' }); // 再发同步 action
}
 
export function* watchIncrementAsync() {
  yield takeEvery('INCREMENT_ASYNC', incrementAsync);
}

(3)加到 rootSaga

yield all([helloSaga(), watchIncrementAsync()]);

至此,你已掌握 saga 的核心 API:takeEveryputdelay

────────────────── 4. 实战:登录 + 获取列表 完整思路:
• 监听 TO_LOGIN_IN → 调用登录接口 → 成功后触发 to_login_in → 同时拉取列表
• 监听 TO_LOGIN_OUT → 触发 to_login_out

import { call, put, take, all } from 'redux-saga/effects';
 
// 工具函数:fetch 封装
const post = (url, body) =>
  fetch(url, { method: 'POST', body: JSON.stringify(body) })
    .then(res => res.json());
 
function* loginFlow() {
  while (true) {
    const { username, password } = yield take('TO_LOGIN_IN');
    try {
      const res = yield call(post, '/api/login', { username, password });
      if (res.status === 10000) {
        yield put({ type: 'to_login_in', user: res.user });
        // 登录成功后拉取列表(可并发)
        yield call(getList);
      } else {
        yield put({ type: 'login_fail', msg: res.msg });
      }
    } catch (e) {
      yield put({ type: 'login_fail', msg: e.message });
    }
 
    // 等待登出
    yield take('TO_LOGIN_OUT');
    yield put({ type: 'to_login_out' });
  }
}
 
function* getList() {
  try {
    const res = yield call(post, '/api/list', {});
    yield put({ type: 'update_list', list: res.data });
  } catch (e) {
    yield put({ type: 'update_list_error', error: e });
  }
}
 
export default function* rootSaga() {
  yield all([loginFlow()]);
}

注意:call 会阻塞,若希望并行/非阻塞,可使用 fork

────────────────── 5. 高频 API 速查表

名称作用示例
takeEveryyield takeEvery('LOGIN', loginSaga) 监听所有 LOGIN
takeLatest仅响应最近一次 action,适合搜索框
take精准一次:const action = yield take('LOGIN')
putsaga 内部再 dispatch
call(fn,…)阻塞调用
fork非阻塞调用,返回 task
select获取当前 state:const s = yield select()
all([…])并发启动多个 saga

────────────────── 6. 典型目录结构(中大型项目)

src/
├── store/
│   ├── index.js          // createStore + sagaMiddleware.run
│   ├── reducers/
│   └── sagas/
│       ├── index.js      // rootSaga
│       ├── userSaga.js
│       └── listSaga.js
├── components/

把每个业务模块的 saga 拆文件,再在 rootSagaall 合并,可维护性最佳。

────────────────── 7. 常见坑 & 调试技巧 • 忘记 sagaMiddleware.run(rootSaga) → saga 不执行
• 忘记 yield → 代码不报错但逻辑不生效
• 阻塞误区:登录后拉取列表若用 call,登出按钮需等待列表返回才能点击;解决办法:fork(getList)spawn(无阻塞)
• 调试:安装浏览器扩展 Redux DevTools,可直接查看 action 流和 effect 日志
• 兼容性:老浏览器需 @babel/polyfill 支持 Generator

────────────────── 8. 继续深造 9. 官方中文教程(含 Counter 完整源码)
https://saga.redux.js.cn/docs/introduction/BeginnerTutorial/
10. 知乎实战:React-Redux-Saga 一条龙
https://zhuanlan.zhihu.com/p/82442831
11. 掘金长文:登录/列表/登出完整案例
https://juejin.cn/post/6844903635747340296

照以上步骤,你可以在一小时内跑通最小 Demo,一天内完成业务接入。祝你编码愉快!