Middleware
在构建store时将middleware作为第二个参数;
import { createStore, combineReducers, applyMiddleware, compose } from 'redux';
const logger = store =>{
return next => {
return action=>{
console.log('[Middleware] Dispatching', action);
const result = next(action); //将action 传入 reducer
console.log('[Middleware] next state', store.getState())
return result;
}
}
}
const store = createStore(rootReducer, applyMiddleware(logger));
Devtools
https://github.com/zalmoxisus/redux-devtools-extension
将Middleware包住,在浏览器中调用reduxdev tools;
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, combineReducers, applyMiddleware, compose } from 'redux';
import counterReducer from './store/reducers/counter';
import resultReducer from './store/reducers/result';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
const rootReducer = combineReducers({
ctr: counterReducer,
res: resultReducer
});
const logger = store =>{
return next => {
return action=>{
console.log('[Middleware] Dispatching', action);
const result = next(action); //将action 传入 reducer
console.log('[Middleware] next state', store.getState())
return result;
}
}
}
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__|| compose;
//配合redux extension
const store = createStore(rootReducer, composeEnhancers(applyMiddleware(logger)));
ReactDOM.render(<Provider store={store}><App /></Provider>, document.getElementById('root'));
registerServiceWorker();
将action变为actionCreators:方便进行异步操作
actions.js
export const INCREMENT = 'INCREMENT';
export const DECREMENT = 'DECREMENT';
export const ADD = 'ADD';
export const SUBTRACT = 'SUBTRACT';
export const STORE_RESULT = 'STORE_RESULT';
export const DELETE_RESULT = 'DELETE_RESULT';
//用action creater 创建 action
export const increment=()=>{ //返回一个obj
return {
type:INCREMENT
};
};
//action creater作为一个function 返回一个obj
export const decrement=()=>{
return {
type:DECREMENT
};
};
export const add =(val)=>{
return {
type:ADD,
val:val
};
};
export const subtract=(val)=>{
return{
type:SUBTRACT,
val:val
};
};
export const store_result=(result)=>{
return{
type:STORE_RESULT,
result:result
};
};
export const delete_result=(id)=>{
return{
type:DELETE_RESULT,
resultElId: id
};
};
counter.js,对上述进行调用
import * as actionCreators from '../../store/actions/actions';
const mapDispatchToProps = dispatch => {
return {
onIncrementCounter: () => dispatch(actionCreators.increment()),
onDecrementCounter: () => dispatch(actionCreators.decrement()),
onAddCounter: () => dispatch(actionCreators.add(10)),
onSubtractCounter: () => dispatch(actionCreators.subtract(15)),
onStoreResult: (result) => dispatch(actionCreators.store_result(result)),
onDeleteResult: (id) => dispatch(actionCreators.delete_result(id))
}
};
Middleware-Redux thunk
https://github.com/reduxjs/redux-thunk
npm install --save redux-thunk
跟随教程,引入applymiddleware,放入state中;
import { createStore, combineReducers, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk'; //引入middleware
在middleware中第二个参数传入thunk;
const store = createStore(rootReducer, composeEnhancers(applyMiddleware(logger,thunk)));
利用middleware使用异步操作
在dispatch中传入的函数,调用一个异步函数,执行dispatch操作;
export const saveResult = (res)=>{
return{
type:STORE_RESULT,
result:res
};
};
//action creator 不返回一个action,而返回一个function——用于dispatch action
//故返回的function与action creator 中的内容是异步的
//返回一个dispatch——> 进行异步操作——两秒后调用saveResult
export const store_result=(result)=>{
return dispatch=>{ //从middleware中得到dispatch
setTimeout(() => {
dispatch(saveResult(result));
}, 2000);
};
};
将actionCreator拆分+合并
actionType.js
export const INCREMENT = 'INCREMENT';
export const DECREMENT = 'DECREMENT';
export const ADD = 'ADD';
export const SUBTRACT = 'SUBTRACT';
export const STORE_RESULT = 'STORE_RESULT';
export const DELETE_RESULT = 'DELETE_RESULT';
counter.js
import * as actionTypes from './actionsType';
//用action creater 创建 action
export const increment=()=>{ //返回一个obj
return {
type:actionTypes.INCREMENT
};
};
//action creater作为一个function 返回一个obj
export const decrement=()=>{
return {
type:actionTypes.DECREMENT
};
};
export const add =(val)=>{
return {
type:actionTypes.ADD,
val:val
};
};
export const subtract=(val)=>{
return{
type:actionTypes.SUBTRACT,
val:val
};
};
result.js
import * as actionTypes from './actionsType';
export const saveResult = (res)=>{
return{
type:actionTypes.STORE_RESULT,
result:res
};
};
//action creator 不返回一个action,而返回一个function——用于dispatch action
//故返回的function与action creator 中的内容是异步的
//返回一个dispatch——> 进行异步操作——两秒后调用saveResult
export const store_result=(result)=>{
return dispatch=>{ //从middleware中得到dispatch
setTimeout(() => {
dispatch(saveResult(result));
}, 2000);
};
};
export const delete_result=(id)=>{
return{
type:actionTypes.DELETE_RESULT,
resultElId: id
};
};
index.js
export {
add,
subtract,
increment,
decrement
} from './counter';
export {
store_result,
delete_result
} from './result';
//将所有文件要export的都放入这儿,方便后面调用
需要import的js都从index中import即可;
异步获取数据后在reduce前改变数据
在action中改变data
export const saveResult = (res)=>{
const updatedResult = res *2;
return{
type:actionTypes.STORE_RESULT,
result:updatedResult
};
};
在reducer中改变data
case actionTypes.STORE_RESULT:
return {
...state,
results: state.results.concat({id: new Date(), value: action.result*2}) //可在这里处理res
}
调用异步时,可传入getState获取当前state
export const store_result=(result)=>{
return (dispatch, getState)=>{ //从middleware中得到dispatch
//getstate得到当前state
setTimeout(() => {
const oldCounter = getState().ctr.counter;
console.log(oldCounter);
dispatch(saveResult(result));
}, 2000);
};
};
优化代码——Utility Functions
reducer中调用return时,将return的obj内容用一个函数返回;
utility.js
export const updateObject = (oldObject, updatedValues)=>{
return {
...oldObject,
...updatedValues //需要更新的obj参数
}
};
reducer
import * as actionTypes from '../actions/actionsType';
import {updateObject} from '../utility';
const initialState = {
counter: 0
};
const reducer = ( state = initialState, action ) => {
switch ( action.type ) {
case actionTypes.INCREMENT:
return updateObject(state,{counter: state.counter + 1});
case actionTypes.DECREMENT:
return updateObject(state,{counter: state.counter - 1});
case actionTypes.ADD:
return updateObject(state,{counter: state.counter + action.val})
case actionTypes.SUBTRACT:
return updateObject(state,{counter:state.counter - action.val});
}
return state;
};
export default reducer;
import * as actionTypes from '../actions/actionsType';
import {updateObject} from '../utility';
const initialState = {
results: []
};
const reducer = ( state = initialState, action ) => {
switch ( action.type ) {
case actionTypes.STORE_RESULT:
return updateObject(state,{results: state.results.concat({id: new Date(), value: action.result})});
case actionTypes.DELETE_RESULT:
const updatedArray = state.results.filter(result => result.id !== action.resultElId);
return updateObject(state,{results: updatedArray});
}
return state;
};
export default reducer;
再细一点
import * as actionTypes from '../actions/actionsType';
import {updateObject} from '../utility';
const initialState = {
results: []
};
const deleteResult=(state, action)=>{
const updatedArray = state.results.filter(result => result.id !== action.resultElId);
return updateObject(state,{results: updatedArray});
};
const reducer = ( state = initialState, action ) => {
switch ( action.type ) {
case actionTypes.STORE_RESULT: return updateObject(state,{results: state.results.concat({id: new Date(), value: action.result})});
case actionTypes.DELETE_RESULT: return deleteResult(state,action);
}
return state;
};
export default reducer;