美文网首页
在项目中引入redux管理数据

在项目中引入redux管理数据

作者: 林不羁吖 | 来源:发表于2021-07-25 17:12 被阅读0次

1.添加redux相关依赖

yarn add redux react-redux redux-thunk

  • react-redux(react组件和redux结合) 比如context,provider共享store
  • redux-thunk 进行异步请求

2.在store文件夹中创建store

store > index.js

2.1 createStore传入的参数

1.reducer

1.项目中的reducer不止一个,因为模块多,不可能所有数据都通过一个reducer进行处理,一般一个模块一个reducer
2.多个reducer必然需要合并
store>reducer.js

import { combineReducers } from 'redux';
const cReducer = combineReducers({
})
export default cReducer;

3.在index.js引入reducer.js

import { createStore } from 'redux';
import reducer from './reducer';

const store = createStore(reducer, );
export default store;

2.enhancer, 对store进行加强

import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import reducer from './reducer';

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
//为了让调试工具的redux起作用,还需要使用composeEnhancers包裹applyMiddleware
const store = createStore(reducer, composeEnhancers(
  applyMiddleware(thunk)
//applyMiddleware 合并多个中间件
));

export default store;

3.App.js导入Provider,store

这样项目就可以使用共享的store了

import React, { memo } from 'react';
import { Provider } from 'react-redux'
import { renderRoutes } from 'react-router-config';
import { HashRouter } from 'react-router-dom'

import routes from './router';
import store from './store'

import AppHeader from 'components/app-header'
import AppFooter from 'components/app-footer'

export default memo(function App() {
    return (
        <Provider store = {store}>
            <HashRouter>
                <AppHeader />
                {renderRoutes(routes)}
                <AppFooter />
            </HashRouter>
        </Provider>
    )
})

4.运行项目报警告,combineReducers中没有有效reducer,创建一个recommend的reducer

为了架构更清晰,一个模块一个store,需要用的时候就可以直接用

  • 1.在recommend目录下新建了store文件夹,

actionCreators.js:调用接口,对返回数据进行处理和储存,
constants.js:action的名称,
index.js:导出reducer,
reducer.js:对数据进行合并

  • 2.reducer.js
    默认状态,reducer方法:根据action(常量)更新state
import * as actionTypes from './constants';
const defualtState = {
    topBanners: []
}

function reducer(state = defualtState, action) {
    switch(action.type) {
        case actionTypes.CHANGE_TOP_BANNERS:
            return {...state, topBanners: action.topBanners }
        default:
            return state;
    }
}

export default reducer;
  • 3.constants.js
    放action 常量
export const CHANGE_TOP_BANNERS = "recommend/CHANGE_TOP_BANNERS";//recommend为模块名
  • 4.index.js
    导出reducer
import reducer from './reducer';

export {
    reducer
}
  • 5.全局store里导入模块的reducer
import { combineReducers} from 'redux';
import { reducer as recommendReducer } from '../pages/discover/c-pages/recommend/store'
const cReducer = combineReducers({
    recommend: recommendReducer
})
export default cReducer;

已经可以在浏览器里redux Chrome插件里看到topBanners

5.在recommend组件里发送网络请求

redux-thunk发起网络请求——>拿到数据data——>通过dispatch传递action对象(包含数据)——>reducer进行数据合并

5.1 拿到数据data的过程

dispatch(函数),函数写在actionCreators里面

import * as actionTypes from './constants'
import { getTopBanners } from '@/services/recommend'

const changeTopBannerAction = (res) => ({
    type: actionTypes.CHANGE_TOP_BANNERS,
    topBanners: res.banners
})
export const getTopBannerAction = () => {
    return dispatch => {
        getTopBanners().then(res => {
            dispatch(changeTopBannerAction(res))//拿到数据,放到reducer里面,需要新的action:changeTopBannerAction 
        })
    }
// 为什么要传入action返回的函数而不是action赋值的函数,因为可能会需要根据传入的参数生成新的函数
}

发送网络请求的时候不会直接在actionCreators中使用request,而是导入对应模块的请求文件。

对于每一个模块可能会发送多个网络请求,所以一个模块一个文件来存放对应的网络请求url等数据。可以增强项目的扩展性。

import request from './request';

export function getTopBanners() {
  return request({
    url: "/banner"
  })
}

5.2 在recommend组件中如何获取dispatch和state

mapStateToProps ,mapDispatchToProps ,connect

import React, { memo, useEffect } from 'react'
import { connect } from 'react-redux' //返回高阶组件
import { getTopBannerAction } from './store/actionCreators'
function XLRecommend(props) {
    const { getBanners, topBanners } = props;
    useEffect(() => {
        getBanners()
    }, [getBanners])
    return (
        <div>
            {topBanners.length}
        </div>
    )
}

const mapStateToProps = state => ({//最完整的state
    topBanners: state.recommend.topBanners
});

const mapDispatchToProps = dispatch => ({
    getBanners: () => {
        dispatch(getTopBannerAction())
    }
});

export default connect(mapStateToProps, mapDispatchToProps)(memo(XLRecommend));

6.用redux的hooks优化和redux的关联代码

  • 如果很多个页面都需要和redux关联起来,这样代码就有点麻烦,所以需要优化
  • 组件和redux的关联需要做:

6.1 获取数据

const {topBanners} = useSelector(state => ({topBanners: state.recommend.topBanners}));

6.2 进行dispatch操作

const dispatch = useDispatch();

import React, { memo, useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { getTopBannerAction } from './store/actionCreators'
function XLRecommend() {
    const {topBanners} = useSelector(state => ({topBanners: state.recommend.topBanners}));
    const dispatch = useDispatch();

    useEffect(() => {
        dispatch(getTopBannerAction());
    }, [dispatch])

    return (
        <div>
            {topBanners.length}
        </div>
    )
}
export default memo(XLRecommend);

6.3 useSelector性能优化

import { useSelector, useDispatch, shallowEqual } from 'react-redux'
const { topBanners } = useSelector(state => ({ topBanners: state.getIn(["recommend", "topBanners"]) }), shallowEqual);

使用useSelector会出现,组件没有使用某个状态,但是状态改变组件会重新渲染,原因是useSelector返回的是一个函数,
而且内部默认做的是全等比较,因为函数每次返回值都不同,所以每次都会触发重新渲染。但是我们希望是做个浅层比较(shallowEqual) {a:aaObj,b:bbObj}
如果是全等比较,没有使用aa,bb状态的组件,在aabb改变时组件会重新渲染,state改变后。
而浅层比较,不会重新渲染,只是比较key有没有变化。

6.4 immutable优化reducer中拷贝旧数据

reducer里的数据在变化时需要拷贝旧数据,所产生的性能和内存消耗问题

    return {...state, topBanners: action.topBanners }
  1. 管理的数据转化为immutable
  • 安装 immutable
  • 选择map还是fromJS,fromJS进行的深层比较,没有什么必要,所以选择map
import { Map } from 'immutable'
...
  return state.set("topBanners",action.topBanners)//会返回新的对象
  1. combineReducers不能使用Map,因为无法直接获取key值,需要安装新的依赖: redux-immutable,可以
    把原来的对象转化为immutable对象
import { combineReducers} from 'redux-immutable';
import { reducer as recommendReducer } from '../pages/discover/c-pages/recommend/store'
const cReducer = combineReducers({
    recommend: recommendReducer
})
export default cReducer;

相关文章

网友评论

      本文标题:在项目中引入redux管理数据

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