记一次愉快项目开发中详细使用redux的过程(配置 + 数据请求)

写在前面
在现在我对于redux的了解基本就属于会做一些简单操作,但是真正在开发中去做一写请求什么的,绝壁狗die,所以我来重新整理一次开发中redux的使用过程,理理思路。虽然现在我不会,maybe,写完这个文章我就豁然开朗了。

------------------------------------------------------------------------------------------------------------------------------------
第一部分首先说说redux各部分都是干什么的?
首先,众所周知,Vue有属于自己的Vuex,作为自己的状态管理神器。
那么react必然也会有自己的状态管理神器。没错,就是redux。
redux的出现,就是为了方便我们管理众多复杂的状态,同时也有利于我们去管理代码,维护代码。
对于redux而言,其下主要有这么几个小弟。

first—>store
store主要负责做什么呢?
store这个弟弟,其主要职责就是通过createStore创建一个store数据点。

seconde —> action
那么action主要负责做什么呢?
action的作用类似于一个古代驿站,全国所有的信件都必须从我这里分发,因此action都是作用于修改数据的,redux官方明确指出,在redux中,必须通过派发(dispatch)action来修改state。

end —> reducer
这个时候肯定有人问了,store和action具体怎么沟通呢?
别着急,古代的驿站都有信使收发信件呢。高端大气上档次的redux怎么会没有个“信使”。
没错,reducer就是用来处理store和action的。
reducer是一个纯函数,通过将state和action结合起来返回一个新的state。这样一次数据的修改就完成了。

这时候问题来了,方便吗?方便吗?方便吗? 肯定是方便的。如果有一天你读过别人的代码,读过自己之前写的代码,你会发现,越复杂的事情,最后一块一块的解析成一个个小规模,就差不多像工厂流水线一样,各自有各自的工作和职责,各司其职,就ok了。

好了,废话不多说。 我直接上项目开发中使用redux的过程了。

------------------------------------------------------------------------------------------------------------------------------------

第二部分: 基本项目开发中我们对redux文件的划分

(1)redux目录结构的划分。
我们日常的开发中,需要将redux代码安排在一个文件夹中。
首先我们创建一个store文件夹。
紧接着,需要创建 index.js,constants.js,reducer.js,actionCreators.js

(2)目录结构如下
在这里插入图片描述
(3)那么每个部分用于做什么呢?

  • reducer.js 这里负责写好reducer纯函数,
import {
    
    
    ADD_NUMBER,
    SUB_NUMBER
} from './constants.js'

const initialState = {
    
    
    counter:0
}

function reducer(state = initialState, action){
    
    
    switch(action.type) {
    
    
        case ADD_NUMBER:
            return {
    
    ...state, counter : state.counter + action.num}
        case SUB_NUMBER:
            return {
    
    ...state, counter : state.counter - action.num}

        default:
            return state;
    }
}


export default reducer;
  • actionCreators.js 这里我们将需要派发的action封装为更加灵活的函数。
//将action封装为更加灵活的函数

import {
    
    
    ADD_NUMBER,
    SUB_NUMBER
} from './constants.js'

export const addAction = num => {
    
    
    return {
    
    
        type:ADD_NUMBER,
        num
    }
}

export const subAction = num => {
    
    
    return {
    
    
        type:SUB_NUMBER,
        num
    }
}

  • constants.js 这里为了放置我们的变量由于使用不统一造成的问题,我们将我们要使用的变量定义为常量。
export const ADD_NUMBER = "ADD_NUMBER";
export const SUB_NUMBER = "SUB_NUMBER";
  • index.js 这里写好store,同时导出页面,供其他组件使用.
import redux from 'redux'

import reducer from './reducer.js'

const store = redux.createStore(reducer);




export default store;

这样看下来,redux貌似也就这个样子,但是当我去真正开项目开发中,redux的使用的时候,我又发现是我草率了。
我有草率了。
草率的总是我!!!!

------------------------------------------------------------------------------------------------------------------------------------
第三部分: 首先在项目中对redux来个简单配置

(1)首先作为一个react初级程序yuan,想必创建如下文件夹就不用本yuan多说了。
在这里插入图片描述

(2)接着,既然我们想要使用redux,那就先添加两个库,redux,以及react-redux,以及redux-thunk,想必大家必定用过,但是可能具体作用记不起来了。
redux — > 状态管理器
react-redux —> 里面有context 以及provider (共享stroe)
redux-thunk —> 做异步请求

(3)ok!还算简单吧! 接下里就进入到我们第一部创建好的文件中。
首先我们去store/index.js 中愉快的创建我们的store数据点。

(4)首先在store下的index.js中我们要去创建store数据点。
index.js 1.0

//index.js
import {
    
     createStore } from 'redux'

const store = createStore();

reducer.js 1.0
根据我上一篇文章积累下来的经验,每一个通过createStore创建出来的store,都需要传入一个reducer对象。
再动动我们的小脑子,一个那么大的项目,肯定有好多数据需要派发管理,所以一个reducer是远远不够的,那么就体现了拆分reducer的重要性,这个上篇文章也讲过了。

import {
    
     combineReducers } from 'redux';

const cReducer = combineReducers({
    
    
    
})

export default cReducer; 

其中,从redux引入的conbinReducers 负责合并各个模块的reducer。
接下来,我们就可以在我们index.js 1.0中引入了我们的reducer了。

index 2.0

import {
    
     createStore } from 'redux';

import  cReducer from './reducer'

const store = createStore(cReducer);

export default store;

在接下来,store中还可以在传入一个参数,可以使用一些中间件,类如redux-thunk,用来处理异步请求。

index3.0

import {
    
     createStore,applyMiddleware } from 'redux';
import thunk from 'redux-thunk'

import  cReducer from './reducer'

const store = createStore(cReducer,applyMiddleware(thunk));

export default store;

这样就算我们对使用redux前的一些简单配置完成了。

接下来使用store进行共享
这个就比较简单了,我们之间安装了react-redux,其中提供了Provider来实现组件间共享store中的状态。
这个我们之间去最外层的App.js中

//首先去react-redux中导入   Provider
//之后去 store中导入我们刚才封装好的数据点store
//最后使用Provider组件,包裹我们页面所有的组件,这样就实现了我们的redux管理我们绝大多数的数据状态。

其中Provider组件中要传入 键值对 store={
    
    store}


import {
    
     Provider } from 'react-redux'
import store from './store'

<Provider store={
    
    store}>
         //这里是你所有的组件
</Provider>

这样,我们项目中要使用的redux基本的配置,就已经完成了。
但是浏览器回报给我们一个这样的错误。
在这里插入图片描述

用我这种没过四级的英语loser都知道,他说我reducer合并的时候返回了个寂寞。所以这个问题先不着急,也不会导致你目前的项目页面渲染。

怎么样,到了这里,我想你已经觉得,就这???
就这??
redux就这?
这个博主居然写两篇这么长的文章。
真为这个博主汗颜。

那我只能说,too young too simple !
真正的redux难点在下一部分。

------------------------------------------------------------------------------------------------------------------------------------
第四部分: 使用redux进行请求数据和管理数据
到了这里,我想大家已经对使用redux开发兴趣满满了,前面我们准备了这么久,想必大家跃跃欲试。那么,我们就来一次数据请求吧。

(1)而对于数据请求而言,我们每一个页面模块的数据请求都应该封装在一个store下,下面同时设置 index.js actionCreators.js constant.js reducer.js 。

(2)目录结构如下
这是一个recommend页面模块下的store文件夹。
在这里插入图片描述

(3)现在文件建好了,在recommend模块内部,我们先开始写哪一个文件呢?
(以下文件均为recommend/store下的文件,大家别定义错文件)

巧了,没错,就是reducer.js
reducer.js 1.0

const defaultState = {
    
    
    topBanners:[]
}

function reducer(state = defaultState, action) {
    
    
    switch(action.type) {
    
    
        case
    }
}



好了,到这里reducer.js 1.0就算完成了,这时候,就差有人来敲我脑袋了,你给我管这个叫做敲完了????
case 后面接你妹啊???

啊 害。。。 别着急。

看了第一篇文章,大家都知道这里的case主要作用于去派发不同的action,因此我们需要去定义不同的action,同时,为了避免我们使用常量错误,所以首先要去constant.js中去定义一些我们要使用的常量。

接下来我们来实现constant.js 1.0 ,因为我们只需要演示一个数据状态的改变,所以示例只有一个常量,不过对于学习redux毫无影响,甚至还有点想笑。

constatnt.js

export const CHANGE_TOP_BANNERS = "CHANGE_TOP_BANNERS"

然后,我们就已经做好了很多事情了,对就这,已经做好了很多事情了。
接下来,我们常量定义好了,可以回过头去完善我们的reducer.js了。
类比一下我们可不是抛妻弃子的渣男,赚钱了就回家养家了。
so 来吧。

reducer.js 2.0

import * as actionTypes from './constants'

const defaultState = {
    
    
    topBanners:[]
}

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

相比于reducer.js 1.0,我们做了什么呢?
首先引入我们的常量,方便我们去识别action,从而派发action。

接下来,我们干了什么呢?
我们定义了默认数据defaultState用来存储我们要请求回来的数据,并且复制为数组类型。

而reducer函数内部做了什么呢?
它通过分析我们dispatch派发的action的type来使用switch case进行判断,从而实现数据的修改。

接下来干什么呢?

不妨去index.js里把我们定义好的reducer分享出去,这样在我们目录框架下的store/reducer里,可以实现reducer的合并。
recommend/store/index.js 1.0

import reducer from './reducer'


export {
    
    
    reducer
}

接下来意味这,我们recommend模块里的reducer算是一个50%的完成状态,这个时候我们可以去目录框架下的store/reducer.js中去合并所有模块的reducer了。

根目录下 store/reducer.js 2.0(这里相较于上面的部分,应该是2.0了奥)

import {
    
     combineReducers } from 'redux';

import {
    
     reducer as recommendReducer } from '../pages/discover/c-pages/recommend/store';

const cReducer = combineReducers({
    
    
    recommend:recommendReducer
})

export default cReducer; 


这里相较于根目录下 store/reducer.js 1.0我们做了什么呢?
首先我们引入了我们刚才在recommen下定义好的reducer,并且我们通过重命名的方式将其修改名称(为什么修改名称,我们说了,模块多的时候,每次封装的都叫做reducer,what should chrome do?)
接着我们只需要将recommend中的reducer引入我们的最终合并的reducer中即可。

------------------------------------------------------------------------------------------------------------------------------------
接下来我们开始来分发网络请求,同时通过派发action,实现数据在redux中进行管理,和在页面上进行渲染。

又因为我们同时需要在封装action的同时去发起网络请求,所以我们应该先去services下创建对应的recommend.js 去封装好recommend要请求的数据,同时暴露出来一个函数,给我们recommend/store/actionCreators.js文件调调用。

service/recommend.js

/**
 * 这里封装所有的recommend下的数据请求
 * 
 */

 import request from './request'

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

好了,recommend就像一个工具人一样,自己啥都干了,最后孩子是别人的。
胜利果实被窃取了。

所以,接下来我们要去写我们的action了,没有错,就是去actionCreators.js中去封装我们所有要使用到的action。
recommend/store/actionCreators.js 1.0

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

那么,在如上的代码中,我们主要做了什么呢?
首先引入了在constant.js中定义的常量,方便我们的action在reducer中进行划分,其次引入了我们axios请求封装好的函数。

在接下来,我们说我们导出的getTopBannerAction,首先,在这个函数中我们进行了数据请求,并且将请求回来的数据同时通过上面的changeTopBannerAction,派发了出去。

ok,这个文件要做的事情已经完成了。

那么接下来,我们就要去我们的recommend页面里面拿到我们的数据了。
首先来讲一下,react-redux中的connect函数。

connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])(MyComponent)

connect是连接React组件与Redux store,建立组件与store.state和dispatch的映射关系。连接操作不会改变原来的组件类。返回一个新的已于Redux store连接的组件类。
mapStateToProps:
mapStateToProps是一个函数,用于建立组件和store.state的映射关系
如果定义了该参数,组件将会监听redux store的变化。只要redux store发生变化,mapStateToProps函数就会被调用。
mapDispatchToProps:
mapDispatchToProps用于建立组件和store.dispatch的映射关系
mapDispatchToProps可以是对象或函数

recommend/index.js

import React, {
    
     memo, useEffect } from 'react';

import {
    
     connect } from 'react-redux';

import {
    
     getTopBannerAction } from './store/actionCreators'

function KJHRecommend(props) {
    
    
    console.log(props)
    const {
    
     getBanners, topBanners} = props;
    useEffect(() => {
    
    
        getBanners();

    }, [getBanners])


    return (
        <div>
            <h2>KJHRecommend : {
    
    topBanners.length}</h2>
        </div>
    )
}


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

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


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

接着,只需要将recommend/store/reducer.js
中代码替换为如下代码即可。

return {
    
    ...state,topBanners:action.topBanners}

接着·,或许这个文件下面处理action,获取数据的过程过于繁琐,既然大家学习了react hooks。所以我们不妨优化一下代码。
recommend/index.js 2.0

import React, {
    
     memo, useEffect } from 'react';

import {
    
     connect, useDispatch, useSelector } from 'react-redux';

import {
    
     getTopBannerAction } from './store/actionCreators'

function KJHRecommend(props) {
    
    
    
    // 组件和redux关联: 获取数据和进行操作
    const dispatch = useDispatch();

    // 发送网络请求
    useEffect(() => {
    
    
        dispatch(getTopBannerAction());
    }, [dispatch])

    //拿到数据
    const {
    
    topBanners} = useSelector(state => ({
    
    
        topBanners: state.recommend.topBanners
    }))
    return (
        <div>
            <h2>KJHRecommend : {
    
    topBanners.length}</h2>
        </div>
    )
}

export default memo(KJHRecommend);

最后,我们通过在useEffect中调用函数,发起请求,同时保存state状态,并且将我们拿到的数据topBanners显示在页面上。

------------------------------------------------------------------------------------------------------------------------------------

写在后面
好了,这样我们redux配置,以及redux的发送请求,保存数据就复习了一遍了,
嗯,博主脑子,貌似有那么点感觉了。
貌似吧。

以后多看看应该就懂了。

有些事情努力是有作用的,有些事情别人说了永远不可能,或许最开始努力到最后都是个百分之0.

猜你喜欢

转载自blog.csdn.net/qq_43955202/article/details/108714076