美文网首页
[react]21、react-redux

[react]21、react-redux

作者: 史记_d5da | 来源:发表于2021-11-22 22:49 被阅读0次

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中发送异步请求


react异步请求

3.3、redux中异步操作

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

redux异步操作

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
});

相关文章

网友评论

      本文标题:[react]21、react-redux

      本文链接:https://www.haomeiwen.com/subject/vyzytrtx.html