React 数据流方案专题(Redux、MobX)

本文详细探讨了React应用中状态管理的两种解决方案:Redux和MobX。Redux是一个JavaScript状态容器,通过可预测化状态管理使得大型项目状态变更易于追踪。其核心包括Store、View、Actions和Reducers,工作流程包括创建Store、定义Reducers和处理Actions。而在React中集成Redux,可以解决数据流管理问题,提高组件间的解耦。同时,文章介绍了Redux中间件的使用,如redux-thunk和redux-saga。另一方面,MobX是一个轻量级的状态管理库,通过observable、action和computed实现数据变化的自动追踪。文章总结了使用Redux和MobX时的关键点和工作流程,为读者提供了深入的理解。
摘要由CSDN通过智能技术生成

Redux专题内容简介:

  • Redux核心
    它是JavaScript的状态容器(就是一个JavaScript对象),提供可预测化的状态管理。在这个容器当中可以保存很多元素的状态。
    在大型项目中,当状态发生变化的时候,使用redux使之变得可预测。当项目当中的状态发生问题的时候,我们可以很容易地定位到问题出现在哪里。

    Redux的核心概念及其工作流程:
            Store:存储状态的容器,是一个JavaScript对象
            View:视图,也就是我们常见的HTML页面,他要想响应store中状态的变化,则需要通过subscribe方法来为视图设置状态的变化订阅。要想对store中的状态进行修改,则需要通过dispatch方法来发布通知要对状态进行的操作Actions,进而调用相对应的Reducers方法以更新store的状态。
            Actions:对象,描述对状态进行怎样的操作
            Reducers:函数,操作状态并返回新的状态(最后会被更新到Store对象中)
    工作流程为:
    1、创建store对象:首先使用Redux.createStore(reducer) 方法创建状态容器Store
    2、创建reducer函数:reducer函数有两个参数,分别为 state 和 action。在reducer函数中,我们可以通过action参数,通过switch判断语句来判断针对所触发(dispatch)的action要进行的状态操作,从而修改并返回修改后的state。该函数会被作为store对象创建时的第一个参数。
    3、声明initialState作为默认的初始状态,它是一个对象,可以作为reducer函数的state参数的默认值。
    4、定义描述要进行的状态变更的action对象
    5、通过在视图中触发相应的操作时,在操作监听的回调函数中通过调用store对象的dispatch(action)(发布通知)方法通知触发相应的action,以此来改变store中的状态。
    6、当页面交互事件触发后就会触发相应的action被reducer接收到,从而作出相对应的状态变更。
    7、当store中的状态发生了改变后,需要同步视图,这是通过调用store.subscribe(callback)来实现的,在callback回调当中进行我们视图的相应操作或者页面内容更新。需要用到当前相应的状态数据可以通过调用store.getState().xxx来获得。store.getState()就是获取store对象中存储的状态。

    总结:redux使用时用到的核心API 如下,
    1)创建Store状态容器
            const store = Redux.createStore(reducer);
    2)创建用于状态处理的reducer函数
            function reducer(state=initialState, action) {...}
    3)获取store容器中的状态
            store.getState()
    4)订阅状态
            store.subscribe(function(){...})
    5)触发Action
            store.dispatch(action); action是一个描述要进行怎样的状态操作的对象,如,{type: 'description...'}
     
  • React + Redux
    在React中使用Redux解决的问题: 组件架构中的数据流向是单向的,只能由父传子,如果没有很好的组织管理这些数据,就会容易造成数据混乱,出现问题时难以定位。
    在react项目中加入redux的好处:使用redux管理数据,由于Store独立于组件,使得数据管理独立于组件,解决了组件与组件之间的数据传递困难的问题。
    工作流程:
    1)组件通过 dispatch 方法触发 action
    2)Store 接受 action, 并将action 分发给 Reducer
    3)Reducer 根据 action 类型对状态进行更改并将更改后的状态返回给 Store
    4)组件订阅了 Store 中的状态,Store 中的状态更新会同步到组件

    要想使之完美结合,我们需要用到 Provider 组件与 connect 方法: react-redux 
    也就是通过Provider组件作为最外部组件,将store 放在全局的组件可以获取的地方。在需要用到Provider提供的store的组件中,引入并使用react-redux的 connect 方法,这个方法内部会帮助我们去订阅store,
    1)不再需要我们手动的去调用store.subscribe方法来订阅状态数据变更。当store中的state状态发生变化的时候,它会帮我们重新渲染这个组件。
    2)通过connect 方法可以拿到store中的状态,使用connect方法的第一个参数(mapStateToProps),可以通过connect当中的方法将store中的状态映射到组件的props属性中,这样一来,我们就可以在组件当中通过props属性来获取组件中的状态了。
    3)通过connect 方法我们还可以拿到 dispatch 方法。

    使用connect方法的第二个参数(mapDispatchToProps)简化组件视图:
    将dispatch方法映射到组件的props属性中。他是一个函数,这个函数要求返回一个对象,在这个返回的对象当中定义什么,那么这些内容都会被映射到组件的props属性中,在组件定义时直接使用props的结构,可以大大简化组件视图的定义。

    bindActionsCreators方法的使用:它是redux当中定义的方法,可以帮助我们生成dispatch发送通知的函数。要告知bindActionsCreators我们要生成的方法名叫什么,要触发的action 是什么。它的第一个参数是一个对象,第二个参数就是dispatch方法,也就是上述connect方法中获得的dispatch函数。bindActionsCreators 方法的返回值就是一个对象。从而方便我们不依赖dispatch方法,抽离重复代码,也就是ActionCreators。

    Action 传递参数:
    在定义ActionCreator的方法定义时可以接受参数,返回包含payload属性的对象,在调用时使用参数进行传递并使用即可。

    拆分合并Reducer:
    需要借助 redux 中提供的 combineReducers 方法,那么reducer最终的返回对象数据结构则发生了变化:
    combineReducers({
        counter: CounterReducer,
        modal: ModalReducer
    })
    
    // 最后的reducer返回对象为: { counetr: {count: 0}, modal: {show: false}}

  • Redux 中间件
    中间件允许我们扩展redux应用程序。它本质上是一个函数,action处理的流程会先经过中间件处理后再交给reducer,让reducer继续处理这个action。
  • 开发Redux中间件
    开发redux中间件有模版代码,他本质就是一个函数。
    // 柯里化函数形式
    export default store => next => action => {}

    只有把创建好的中间件注册给store,那他才能够在redux的工作流程中生效。它的注册需要使用到redux的一个 applyMiddleware 方法,这个方法就是用来注册中间件的,该方法的返回值放在 createStore 方法的第二个参数中,这样一来,当组件去触发action的时候,这个中间件的代码就可以得到执行了。
    如果注册的中间件有多个,那么它的执行顺序是如何的呢?
    它会按照注册的顺序分别调用相对应的中间件,当第一个中间件调用执行完成以后,它里面会调用next方法返回action对象传递给下一个中间件,依次类推。
    注意:中间件必须要调用next(action),把action 外后面传递,后面的中间件以及最后的reducer才能正确的接收到action并执行。

    值得注意的是:
    1、当前的中间件函数是不关心你想执行什么样的异步操作的,只关心你执行的是不是异步操作。
    2、如果你执行的是异步操作,你在触发action的时候给中间件传递一个函数, 如果执行的是同步操作,就传递action对象。
    3、异步操作代码要写在传递进来的函数当中。
    4、当前这个中间件函数在调用你传递进来的函数时,要将dispatch 方法传递进来。
     

    export default ({dispatch}) => next => action => {
        if(typeof action === 'function') {
            return action(dispatch)
        }
        next(action)
    }

  • Redux实践 综合案例
    工作中常见常用中间件:
    1) redux-thunk。运行我们在redux工作流中加入异步代码。
    2)redux-saga。解决的问题是可以将异步操作从action creator 中抽离出来,放在一个单独的文件中。takeEvery 接收action。put 触发action。delay 设置执行延迟时间。
    合并用到all方法,传入一个数组。
    3)redux-actions。帮我门解决的问题是redux流程中大量的样板代码读写很痛苦,使用redux-actions 可以简化 action 和 reducer 的处理。
    // 使用 redux-actions 来创建 action
    import { createAction } from 'redux-actions'
    
    const increment_action = createAction('increment') // 第一个字符串就是原来我们所创建的action对象中 type 的属性值
    const decrement_action = createAction('decrement')
    这里的 createAction就相当于我们之前自己所定义ActionCreator 函数。
    redux-actions 中还有一个方法是用来为上边定义的action 创建对应的 reducer 处理函数逻辑的,它就是 handleActions 方法。该方法的返回值就是我们之前自己创建的那个reducer 函数。
    // counter reducer 使用 redux-actions 来实现
    import { handleActions as createReducer } from 'redux-actions'
    import { increment_action, decrement_action } from '../actions/counter.action'
    
    const initialState = {count: 0}
    
    const counterReducer = createReducer({
        [increment_action]: (state, action) => ({ count: state.count + 1}),
        [decrement_action]: (state, action) => ({ count: state.count - 1})
    }, initialState)
    
    export default counterReducer
    shopping购物车案例进本实现思路:
    服务器的异步请求交由redux-saga处理;
    页面本地store的数据交由redux 的 reducer 来处理;
    action由redux-actions来简化创建。

Redux源码实现:核心逻辑
redux中主要是一个createStore方法,该方法接收三个参数,createStore(reducer, preloaddedState, enhancer)。
reducer 是根据action的 类型来对 store 当中的状态进行更改。
preloadedState 是预先存储的初始化state 状态对象。
enhancer 是对store的功能进行增强,是我们所说的插件应用。
 

// redux的核心逻辑 createStore 方法

function createStore(reducer, preloadedState, enhancer) {
    // 保存初始化store 状态对象, 需要在后续的方法中使用到,所需需要在方法中形成闭包,以便该值不会在createStore方法调用后被回收
    var currentState = preloadedState;
    var listeners = [];

    // 定义getState 方法,返回当前store 中的currentState 对象
    function getState() {
        return currentState;
    }

    // 定义 dispatch 方法,用于触发action, 从而把action 交给 reducer 进行处理,并且将reducer处理过后的返回值更新到 currentState 的引用上,最后遍历所有已注册的订阅者,触发相对应的后续操作,如页面更新等
    function dispatch (action) {
        // 把action 交给 reducer 进行处理,并且将reducer处理过后的返回值更新到 currentState 的引用上
        currentState = reducer(action);
        // 遍历所有已注册的订阅者,触发相对应的后续操作,如页面更新等
        for(let i = 0; i<= listeners.length; i++) {
            var listener = listeners[i]
            listener()
        }
    }
    
    // 定义subscribe 方法,用于为store 添加的订阅者
    function subscribe(listener) {
        listeners.push(listener)
    }

    return {
        getState, // 获取store的状态
        dispatch, // 触发action
        subscribe // 订阅状态
    }
    
}

上面的代码实现过去简单粗暴,对参数的类型没有做限制,但参数不符合的时候没有错误提示,整个运行会直接挂掉。所以这里我们需要改进一下,对一些细节问题作容错处理。
1、 reducer 参数的类型必须是一个函数,该函数有两个参数,state 和 action 分别指示 store 中的状态以及本次action的对象。
2、是判断 dispatch 方法中的参数对象,action 中是否是对象,且对象中包含type 属性。

// redux的核心逻辑 createStore 方法

function createStore(reducer, preloadedState, enhancer) {

    // 约束reducer 参数类型,它必须是一个function 类型
    if(typeof reducer !== 'function') throw new TypeError('reducer must be a function');

    // 保存初始化store 状态对象, 需要在后续的方法中使用到,所需需要在方法中形成闭包,以便该值不会在createStore方法调用后被回收
    var currentState = preloadedState;
    var listeners = [];

    // 定义getState 方法,返回当前store 中的currentState 对象
    function getState() {
        return currentState;
    }

    // 定义 dispatch 方法,用于触发action, 从而把action 交给 reducer 进行处理,并且将reducer处理过后的返回值更新到 currentState 的引用上,最后遍历所有已注册的订阅者,触发相对应的后续操作,如页面更新等
    function dispatch (action) {
        // 判断action 是否为对象
        if(!isPlainObject(action)) throw new TypeError('action must be a plain object');

        // 判断action 对象中是否有type 属性
        if(typeof action.type === 'undefined') throw new Error('action object must contain a type property'
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值