react 整合原生 redux(三)
前言
在react 整合原生 redux(一)的基础上,加上 redux-saga 可以对 reducer 进行扩展,不同于redux-thunk,saga 将 redux 分为两个部分,一部分是同步更新数据,一部分是异步操作,换言之一部分是纯保存,一部分是带有逻辑的保存,而 thunk 仅扩展了 action,使 action 带有逻辑性,两者的目标都是为了降低代码耦合
项目创建
增加依赖包
yarn add redux-saga -s
src 文件目录
|-app.js
|-store.js
|-index.js
|-effects.js
新增effects.js文件
store.js 扩展调整
主要引入redux-saga中间件并使用,基本步骤如下
- saga 引入
import createSaga from "redux-saga"
- saga 初始化
const saga = createSaga()
- saga 作为中间件使用
createStore(reducer, composeWithDevTools(applyMiddleware(saga)))
- saga 运行
saga.run(effect)
具体代码
// store.js
import { createStore, applyMiddleware } from "redux";
import createSaga from "redux-saga";
import { composeWithDevTools } from "redux-devtools-extension"; //chrome redux调试工具
import effect from "./effects";
// state初始值
const initState = {
list: ["a", "b"]
};
// reducer格式
const reducer = (state = initState, action) => {
const { type, payload } = action;
// action的type处理
if (type === "SAVE") {
return Object.assign({}, state, payload);
}
return state;
};
const saga = createSaga();
/**
* 实例化store
* 参数1: reducer
* 参数2: 中间件
*/
export default createStore(reducer, composeWithDevTools(applyMiddleware(saga)));
// 运行saga, 参数是一个生成器函数
saga.run(effect);
effects.js 增加编写
具体看代码,关键部分都有注释
// actions.js
import { call, put, takeEvery } from "redux-saga/effects";
const fetchListEffect = function*(action) {
const { payload } = action;
// 异步操作可直接调用返回promise的函数,如fetch.axios等,官方推荐用call封装一下,具体看updateListApi
const { data } = yield new Promise(resolve => {
setTimeout(() => {
const data = {
code: 0,
msg: "ok",
data: {
list: ["hello", "saga"],
payload
}
};
resolve(data);
}, 2000);
});
yield put({ type: "SAVE", payload: data }); // 这里的put就是store.dispatch的封装
};
/**
* 这个函数可以拆分到service文件中,进一步降低耦合
* @param {参数} payload
*/
const updateListApi = payload => {
return new Promise(resolve => {
setTimeout(() => {
const data = {
code: 0,
msg: "ok",
data: {
list: ["hello", "saga", "update"],
payload
}
};
resolve(data);
}, 1000);
});
};
const updateListEffect = function*(action) {
const { payload } = action;
const { data } = yield call(updateListApi, payload); // 异步数据操作官方推荐用call函数调用 参数1为返回promise的函数,参数2为传递参数
yield put({ type: "SAVE", payload: data });
};
// saga调用的为生成器函数
export default function*() {
// takeEvery参数1 为action的type名 参数2是一个生成器函数
yield takeEvery("fetch/list", fetchListEffect);
yield takeEvery("update/list", updateListEffect);
}
使用,app.js 改写
主要操作
useEffect(() => {
store.dispatch({ type: "fetch/list", payload: { id: 1 } });
}, []);
onClick={() => store.dispatch({ type: "update/list" })}
完整代码
// app.js
import React, { useState, useEffect } from "react";
import store from "./store";
export default () => {
// 获取store中的state,并放进hook函数,类似this.setState(store.getState())
const [state, setState] = useState(store.getState());
useEffect(() => {
// store订阅函数,当state通过store.dispatch分发action改变时此函数自动执行
store.subscribe(() => {
setState(store.getState()); //重新设置组件state的值,使视图更新
});
}, []); // []表示只执行一次
const { list } = state;
const addList = () => {
list.push(Date.now());
store.dispatch({ type: "SAVE", payload: { list } }); //分发一个action对象
};
// 初始化请求数据saga模式
useEffect(() => {
store.dispatch({ type: "fetch/list", payload: { id: 1 } });
}, []);
return (
<div>
<button onClick={addList}>add</button>
{/* 点击事件定义,saga模式 */}
<button onClick={() => store.dispatch({ type: "update/list" })}>
update
</button>
<ul>
{list.map(v => {
return <li key={v}>{v}</li>;
})}
</ul>
</div>
);
};
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。