1、redux文件结构拆分

2、自定义connect函数
2.1、connect.js
connect.js文件依赖于store,可以通过Provider来创建一个Context,让用户将store传入到value中
//utils/connect.js
import React, { PureComponent } from 'react'
import {StoreContext} from './context'
export function connect(mapStateToProps, mapDispatchToProp) {
return function enhanceHOC(WrappedComponent) {
class EnhanceComponent extends PureComponent {
constructor(props, context) {
super(props, context);
this.state = {
storeState: mapStateToProps(context.getState())
}
}
componentDidMount() {
this.unsubscribe = this.context.subscribe(() => {
this.setState({
storeState: mapStateToProps(this.context.getState())
})
})
}
componentWillUnmount() {
this.unsubscribe()
}
render() {
return <WrappedComponent {...this.props}
{...mapStateToProps(this.context.getState())}
{...mapDispatchToProp(this.context.dispatch)}/>
}
}
EnhanceComponent.contextType = StoreContext;
return EnhanceComponent;
}
}
2.2、context.js
import React from 'react'
const StoreContext = React.createContext()
export {StoreContext}
2.3、index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import {StoreContext} from './utils/context'
//import {Provider} from 'react-redux'
import store from './store'
ReactDOM.render(
<StoreContext.Provider value={store}>
<App />
</StoreContext.Provider>,
document.getElementById('root')
);
3、react-redux使用
3.1、安装
redux官方帮助我们 提供了 react-redux 的库,可以直接在项目中使用
yarn add react-redux
3.2、组件中异步操作
网络请求可以在class组件的componentDidMount中发送异步请求

3.3、redux中异步操作
在redux中进行异步的操作使用中间件(Middleware)
Middleware可以帮助我们在请求和响应之间嵌入一些操作的代码,比如cookie解析、日志记录、文件压缩等操作

3.4、中间件redux-thunk
1、中间件的介绍
中间件的目的是在dispatch的action和最终达到的reducer之间,扩展一些自己的代码
比如日志记录、调用异步接口、添加代码调试功能等等
官网推荐的、包括演示的网络请求的中间件是使用 redux-thunk。
redux-thunk是如何做到可以发送异步的请求呢:
- 默认情况下的dispatch(action),action需要是一个JavaScript的对象
- redux-thunk可以让dispatch(action函数),action可以是一个函数
- 该函数会被调用,并且会传给这个函数一个dispatch函数和getState函数;
- dispatch函数用于我们之后再次派发action;
- getState函数考虑到我们之后的一些操作需要依赖原来的状态,用于让我们可以获取之前的一些状态;
2、redux-thunk
1)、安装redux-thunk
yarn add redux-thunk
2)、在创建store时传入应用了middleware的enhance函数
- 通过applyMiddleware来结合多个Middleware, 返回一个enhancer;
- 将enhancer作为第二个参数传入到createStore中;
const enhancer = applyMiddleware(thunkMiddleWare)
const store = redux.createStore(reducer, enhancer);
3)、定义返回一个函数的action,这里不是返回一个对象了,而是一个函数,该函数在dispatch之后会被执行
对应的action
export const changeBannersAction = banners => ({
type: CHANG_BANNERS,
banners
})
export const changeRecommendAction = (recommends) => ({
type: CHANG_RECOMMENDS,
recommends
})
export const getHomeMutildataAction = (dispatch, getState) => {
console.log('getHomeMutildataAction')
axios({
url: 'http://123.207.32.32:8000/home/multidata'
}).then((res) => {
const data = res.data.data
console.log(res)
dispatch(changeBannersAction(data.banner.list))
dispatch(changeRecommendAction(data.recommend.list))
})
}
3.5、redux-devtools调试
redux官网为我们提供了redux-devtools的工具,利用这个工具,我们可以知道每次状态是如何被修改的,修改前后的状态变化
安装该工具需要两步:
1、在对应的浏览器中安装相关的插件Redux DevTools
2、在代码中需要添加:
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({trace: true}) || compose;
const store = redux.createStore(reducer, composeEnhancers);
3.6、中间件redux-saga
redux-saga是另一个比较常用在redux发送异步请求的中间件,它的使用更加的灵活
1、安装redux-saga
yarn add redux-saga
2、集成redux-saga中间件
saga.js文件内容
import axios from 'axios';
import {takeEvery, put, all, takeLatest} from 'redux-saga/effects'
import { changeBannersAction, changeRecommendAction } from './home/actionCreators';
import {
FETCH_HOME_MULTIDATA
} from './home/constants'
function * fetchHomeMultidata(action) {
const res = yield axios.get("http://123.207.32.32:8000/home/multidata")
const banners = res.data.data.banner.list;
const recommends = res.data.data.recommend.list;
// 1、
// yield put(changeBannersAction(banners));
// yield put(changeRecommendAction(recommends));
yield all([
yield put(changeBannersAction(banners)),
yield put(changeRecommendAction(recommends))
])
}
function * mySaga() {
// takeLatest 一次只能监听一个对应的action
// takeEvery 每一个都会被执行
yield all([ // 监听多个
yield takeEvery(FETCH_HOME_MULTIDATA, fetchHomeMultidata ) // 需要拦截的action
])
}
export default mySaga;
store.js文件
import {createStore, applyMiddleware, compose} from 'redux'
import thunkMiddleWare from 'redux-thunk'
import createSagaMiddleware from 'redux-saga'
import * as redux from 'redux'
import reducer from './reducer.js'
import mySaga from './saga.js'
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({trace: true}) || compose;
// 应用一些中间件
// 1、应用thunkMiddleware中间件
// 2、创建createSagaMiddleware中间件
const sagaMiddleware = createSagaMiddleware()
const storeenhancer = applyMiddleware(thunkMiddleWare, sagaMiddleware )
const store = redux.createStore(reducer, composeEnhancers(storeenhancer));
sagaMiddleware.run(mySaga)
export default store;
3.7、中间件的实现
import { addAction, subAction } from './store/actionCreators.js';
import store from './store/index.js'
store.subscribe(() => {
console.log(store.getState());
})
// store.dispatch(addAction(10));
// store.dispatch(addAction(15));
//3、 hack技术 monkeyingpatch
/*
const next = store.dispatch;
function dispatchAndLogging(action) {
console.log("dispatch前---dispatching action:", action);
next(action);
console.log("dispatch后---new state:", store.getState());
}
store.dispatch = dispatchAndLogging;
store.dispatch(addAction(10));
store.dispatch(addAction(5));
*/
// 4、对函数做一次封装
function patchLogging(store) {
const next = store.dispatch;
function dispatchAndLogging(action) {
console.log("dispatch前---dispatching action:", action);
next(action);
console.log("dispatch后---new state:", store.getState());
}
// store.dispatch = dispatchAndLogging;
return dispatchAndLogging
}
patchLogging(store);
store.dispatch(addAction(10));
store.dispatch(addAction(5));
// ---------------------------------------------
// 4封装 patchThunk 功能
function patchThunk(store) {
const next = store.dispatch;
function dispatchAndThunk(action) {
if (typeof action === 'function') {
action(store.dispatch, store.getState);
} else {
next(action);
}
}
// store.dispatch = dispatchAndThunk
return dispatchAndThunk
}
patchThunk(store);
function foo(dispatch, getState) {
dispatch(subAction(10))
console.log(dispatch, getState);
}
store.dispatch(foo);
// 5、封装函数 applyMiddleware
function applyMiddlewares(...middleWares) {
middleWares.forEach(middleware => {
store.dispatch = middleware(store);
})
}
applyMiddlewares(dispatchAndLogging, dispatchAndThunk);
3.8、reducer拆分
// counterReducer
const initialCounterState = {
counter: 0
}
function counterReducer(state = initialCounterState, action) {
switch(action.type) {
case ADD_NUMBER:
return {...state, counter: state.counter + action.num}
case SUB_NUMBER:
return {...state, counter: state.counter - action.num}
case INCREMENT:
return {...state, counter: state.counter + 1}
case DECREMENT:
return {...state, counter: state.counter - 1}
default:
return state;
}
}
// homeReducer
const initialHomeState = {
banners: [],
recommends: []
}
function homeReducer(state = initialHomeState, action) {
switch(action.type) {
case CHANG_BANNERS:
return {...state, banners: action.banners}
case CHANG_RECOMMENDS:
return {...state, recommends: action.recommends}
default:
return state;
}
}
const reducer = combineReducers({
counteInfo: counterReducer,
homeInfo: homeReducer
});
网友评论