Redux-thunk的使用
实现思路
在action中设置一个为函数的action,因为thunk中间件可以执行action函数。
本示例的表达的意思:
- 页面需要获取到接口中的data数据,调用getListDataAction函数。
- getListDataAction函数返回的参数不是一个对象,而是一个函数。
- 这个action派发后,thunk中间件识别后,会执行该函数,在异步获取到数据后,会再派发type为GET_LIST_DATA的action。
- store会再次收到一个新的action,在这个action中,store会去匹配reducer中的内容,执行相应的操作后,返回一个新的state。
- 页面订阅了state的变化,通过setState改变了state,从而将数据存储到state中,页面也会自动刷新。
安装redux-thunk
npm install redux-thunk
// 或者
yarn add redux-thunk
在store文件中使用
import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import reduer from "./reduer";
const composeEnhancers =
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;
const enhancer = composeEnhancers(
applyMiddleware(thunk)
);
const store = createStore(reduer, enhancer);
export default store;
在action文件中定义
import axios from "axios";
import { ADD_VALUE, CHANG_VALUE, DEL_VALUE, GET_LIST_DATA, GET_LIST } from "./actiontypes";
export const getChangeAction = (e) => {
return {
type: CHANG_VALUE,
value: e.target.value
};
}
export const getAddAction = () => {
return {
type: ADD_VALUE
};
}
export const getDelAction = (index) => {
return {
type: DEL_VALUE,
index
};
}
export const getList = () => {
return {
type: GET_LIST
}
}
export const getListData = (data) => {
return {
type: GET_LIST_DATA,
data
}
}
export const getListDataAction = () => {
// 默认store只能识别对象的action,但是使用了thunk,可以通过传入一个函数,在thunk中间件中会执行
return (dispatch) => {
axios.get("api/todolist").then(res => {
const action = getListData(res.data);
dispatch(action);
}).catch((e) => {
console.log("获取数据失败了", e)
})
}
}
在页面组件中使用
componentDidMount() {
const action = getListDataAction();
store.dispatch(action)
}
Redux-saga的使用
实现的思路
首先需要在store中创建saga中间件,该中间件用于监控当前页面中派发的action,根据action中的type参数进行筛选,匹配成功的则执行对应的函数。
设置好了saga之后,页面中根据不同的情况,派发不同的action,当store获取到action之后,saga中间件就会执行,在对应的函数中执行完成后,可以再派发action,用于执行下一步操作。
本示例的意思就是:
- 页面想要获取到接口中的list数据,所以派发type为GET_LIST 的action。
- 当store要执行派发的action的时候,根据saga中间件中的内容,如果有监控GET_LIST的函数,那么就要执行函数getListData。
- 在函数getListData中,发送了axios请求,获取到数据了,那么我需要将获取到的数据存到state中,所以,请求成功后,我需要再派发type为GET_LIST_DATA 的action。
- store会再次收到一个新的action,在这个action中,store会去匹配reducer中的内容,执行相应的操作后,返回一个新的state。
- 页面订阅了state的变化,通过setState改变了state,从而将数据存储到state中,页面也会自动刷新。
安装 redux-saga
yarn add redux-saga
// 或者
npm install redux-saga
在store文件中使用
import { createStore, applyMiddleware, compose } from 'redux';
//
import createSagaMiddleware from 'redux-saga'
import reduer from "./reduer";
import mySaga from './sagas'
// 创建saga中间件
const sagaMiddleware = createSagaMiddleware();
// 此处内容是为了实现react-devtools的调试,配置内容参考:https://github.com/zalmoxisus/redux-devtools-extension
const composeEnhancers =
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;
const enhancer = composeEnhancers(
applyMiddleware(sagaMiddleware)
);
const store = createStore(reduer, enhancer);
// 执行中间件
sagaMiddleware.run(mySaga)
export default store;
创建sagas文件
import { put, takeEvery } from "redux-saga/effects";
import { GET_LIST } from "./actiontypes";
import { getListDataAction } from "./renderStore"
import axios from "axios";
// 获取数据的函数
function* getListData() {
try {
// 使用异步的方式,拿到请求的结果
const res = yield axios.get("api/todolist");
// 获取到新的action
const action = getListDataAction(res.data);
// 派发新的action
yield put (action)
} catch (error) {
console.log("请求todolist数据失败了", error);
}
}
// 监控派发内容是 GET_LIST,都要执行一次 getListData函数
function* mySaga() {
yield takeEvery(GET_LIST, getListData);
}
export default mySaga;
在页面组件中使用
// 在生命周期函数中执行
componentDidMount() {
const action = getList();
store.dispatch(action)
}
Redux公共部分
actiontypes.js文件内容
export const CHANG_VALUE = "change_value";
export const ADD_VALUE = "add_value";
export const DEL_VALUE = "del_value";
export const GET_LIST_DATA = "get_list_data";
export const GET_LIST = "get_list";
rederStore.js中的内容
import { ADD_VALUE, CHANG_VALUE, DEL_VALUE, GET_LIST_DATA, GET_LIST } from "./actiontypes";
export const getChangeAction = e => {
return {
type: CHANG_VALUE,
value: e.target.value
};
}
export const getAddAction = () => {
return {
type: ADD_VALUE
};
}
export const getDelAction = index => {
return {
type: DEL_VALUE,
index
};
}
export const getList = () => {
return {
type: GET_LIST
}
}
export const getListDataAction = data => {
return {
type: GET_LIST_DATA,
data
}
}
reducer.js内容
import { CHANG_VALUE, ADD_VALUE, DEL_VALUE, GET_LIST_DATA } from "./actiontypes";
const defaultState = {
inputValue: "",
list: []
};
// eslint-disable-next-line import/no-anonymous-default-export
export default ((state = defaultState, action: any) => {
if (action.type === CHANG_VALUE) {
const newState = JSON.parse(JSON.stringify(state));
newState.inputValue = action.value;
return newState
}
if (action.type === ADD_VALUE) {
const newState = JSON.parse(JSON.stringify(state));
newState.list.push(state.inputValue);
newState.inputValue = "";
return newState
}
if (action.type === DEL_VALUE) {
const newState = JSON.parse(JSON.stringify(state));
newState.list.splice(action.index, 1);
return newState
}
if(action.type === GET_LIST_DATA) {
const newState = JSON.parse(JSON.stringify(state));
newState.list = action.data;
return newState
}
return state
});