精华内容
下载资源
问答
  • Redux原理

    千次阅读 2018-09-04 20:39:12
    Redux 原理实现 store的创建 注:本文适合有使用过Redux或者有了解过的童鞋阅读~ 接触过的项目很多都用到了Redux,在今天之前,我只是会使用这个工具来进行数据的存储与处理,觉得这真是个好东西,毕竟...

    注:本文适合有使用过Redux或者有了解过的童鞋阅读~

    接触过的项目很多都用到了Redux,在今天之前,我只是会使用这个工具来进行数据的存储与处理,觉得这真是个好东西,毕竟在一个大的项目中,单单靠props、state、ref来传递数据还是不够的。
    面试的时候也被问到了Redux的原理,但是只答了它的用法,没答上它的原理。学习不仅做到知其然,还要做到知其所以然。今天抽了个时间去了解了一下,其实也就那么回事吧~哈哈哈

    Redux基本思想

    保证数据的单向流动,同时便于控制、使用、测试。

    Redux核心概念

    • action
      只是描述要发生的事件,并不改变state

    • reducer
      根据action的描述,改变state

    • dispatch
      将要发生的事件,分发到reducer,触发改变。store.dispatch(action)

    • store
      用来保存state;
      提供 getState() 方法获取 state;
      提供 dispatch(action) 方法更新 state;
      通过 subscribe(listener) 注册监听器;
      通过 subscribe(listener) 返回的函数注销监听器。

    Redux 原理实现

    store的创建

    var createStore = require('redux').createStore;
    var store = createStore(count);//count是个reducer

    先看看createStore都返回了什么?

    export default function createStore(reducer, initialState) {
      ...
      return {
        dispatch,
        subscribe,
        getState,
        replaceReducer
      }
    }

    可以看到,createStore接受两个参数:改变state的reducer和初始state

    每个属性的含义是:

    • dispatch: 用于action的分发,改变store里面的state
    • subscribe: 注册listener,store里面state发生改变后,执行该listener
    • getState: 读取store里面的state
    • replaceReducer: 替换reducer,改变state修改的逻辑

    createStore关键代码解析

    export default function createStore(reducer, initialState) {
      var currentReducer = reducer
      var currentState = initialState
      var listeners = []
      var isDispatching = false;
    
      // 返回当前的state
      function getState() {
        return currentState
      }
    
      // 注册listener,同时返回一个取消事件注册的方法
      function subscribe(listener) {
        listeners.push(listener)
        var isSubscribed = true
    
        return function unsubscribe() {
          if (!isSubscribed) {
             return
          }
          isSubscribed = false
          var index = listeners.indexOf(listener)
          listeners.splice(index, 1)
        }
      }
      // 通过action该改变state,然后执行subscribe注册的方法
      function dispatch(action) {
        try {
          isDispatching = true
          currentState = currentReducer(currentState, action)
        } finally {
          isDispatching = false
        }
        listeners.slice().forEach(listener => listener())
        return action
      }
    
      // 替换reducer,修改state变化的逻辑
      function replaceReducer(nextReducer) {
        currentReducer = nextReducer
        dispatch({ type: ActionTypes.INIT })
      }
      // 初始化时,执行内部一个dispatch,得到初始state
      dispatch({ type: ActionTypes.INIT })
    }
    

    保证store的唯一性

    为每个reducer创建一个store,后期维护比较麻烦,通过combineReducers将多个reducer合并成一个rootReducer:
    用法:

    var combineReducers = require('redux').combineReducers;
    var rootReducer = combineReducers({
      count: count,
      year: year,
    });
    // 创建store
    var createStore = require('redux').createStore;
    var store = createStore(rootReducer);

    combineReducers源码分析:

    export default function combineReducers(reducers) {
      const reducerKeys = Object.keys(reducers)
      const finalReducers = {}
      //将合法的reducer提出来
      for (let i = 0; i < reducerKeys.length; i++) {
        const key = reducerKeys[i] 
        if (typeof reducers[key] === 'function') {
          finalReducers[key] = reducers[key]
        }
      }
      const finalReducerKeys = Object.keys(finalReducers)
      //返回一个reducer,同样接受两个参数,state和action
      return function combination(state = {}, action) {
        let hasChanged = false
        const nextState = {}
        for (let i = 0; i < finalReducerKeys.length; i++) {
          const key = finalReducerKeys[i]
          const reducer = finalReducers[key]
          const previousStateForKey = state[key]
          const nextStateForKey = reducer(previousStateForKey, action)    
          nextState[key] = nextStateForKey
          hasChanged = hasChanged || nextStateForKey !== previousStateForKey
        }
        return hasChanged ? nextState : state
      }
    }

    与react框架的结合

    利用react-redux工具实现二者的结合
    用法:

    var Provider = require('react-redux').Provider;
    // App 为上层的Component
    class App extend React.Component{
      render() {
        return (
          <Provier store={store}>
            <MyComponent />
          </Provider>
        );
      }
    }
    
    var connect = require('react-redux').connect;
    var actionCreators = require('...');
    // MyComponent是与redux无关的组件
    var MyComponent = require('...');
    
    function select(state) {
      return {
        count: state.count
      }
    }
    export default connect(select, actionCreators)(MyComponent)

    Provider原理

    React通过Context属性,可以将属性(props)直接给子孙component,无须通过props层层传递, Provider仅仅起到获得store,然后将其传递给子孙元素而已:

    export default class Provider extends Component {
      getChildContext() { // getChildContext: 将store传递给子孙component
        return { store: this.store }
      }
    
      constructor(props, context) {
        super(props, context)
        this.store = props.store
      }
    
      componentWillReceiveProps(nextProps) {
        const { store } = this
        const { store: nextStore } = nextProps
    
        if (store !== nextStore) {
          warnAboutReceivingStore()
        }
      }
    
      render() {
        let { children } = this.props
        return Children.only(children)
      }
    }
    

    connect原理

    connect函数接受四个参数,分别是:

    • mapStateToProps(state,ownProps):指定如何把当前Redux store state映射到展示组件的props中
    • mapDispatchToProps(dispatch,ownProps):接受dispatch方法并返回期望注入到展示组件的props中的回调方法
    • mergeProps:
    • options:

    connect函数返回一个生产Component的函数(wrapWithConnect),然后再将真正的Component作为参数传入,这样就生产出一个经过包裹的Connect组件,该组件通过this.context获取祖先Component的store,props包括stateProps、dispatchProps、parentProps,合并在一起得到nextState,作为props传给真正的Component

    export default function connect(mapStateToProps, mapDispatchToProps, mergeProps, options = {}) {
      return function wrapWithConnect(WrappedComponent) {
        class Connect extends Component {
          constructor(props, context) {
            // 从祖先Component处获得store
            this.store = props.store || context.store
            this.stateProps = computeStateProps(this.store, props)
            this.dispatchProps = computeDispatchProps(this.store, props)
            this.state = { storeState: null }
            // 对stateProps、dispatchProps、parentProps进行合并
            this.updateState()
          }
          shouldComponentUpdate(nextProps, nextState) {
            // 进行判断,当数据发生改变时,Component重新渲染
            if (propsChanged || mapStateProducedChange || dispatchPropsChanged) {
              this.updateState(nextProps)
                return true
              }
            }
            componentDidMount() {
              // 改变Component的state
              this.store.subscribe(() = {
                this.setState({
                  storeState: this.store.getState()
                })
              })
            }
            render() {
              // 生成包裹组件Connect
              return (
                <WrappedComponent {...this.nextState} />
              )
            }
          }
          Connect.contextTypes = {
            store: storeShape
          }
          return Connect;
        }
      }
    展开全文
  • redux 原理

    2021-02-28 12:49:18
    redux 原理1、Redux 是什么,如何用?2、为什么需要redux?3、Redux几个概念4、Redux 使用的三大原则:5、绑定库 react-reduxRedux工作流程:Store 1、Redux 是什么,如何用? Redux 是 JavaScript 状态容器,提供可...

    1、Redux 是什么,如何用?

    Redux 是 JavaScript 状态容器,提供可预测化的状态管理。Redux 除了和 React 一起用外,还支持其它界面库。它体积很小,只有 2kb ,包括依赖。

    2、为什么需要 redux?

    • 1.跨组件实现 state 共享,尤其是兄弟组件之间,不使用 redux 需要在父组件中写一个状态,让兄弟组件共享这个状态
    • 2.某个状态需要在任何地方都可以拿到
    • 3.一个组件需要改变全局状态
    • 4.一个组件需要改变另一个组件的状态

    3、Redux 中的概念

    • 1.store: 是一个容器/仓库,存放整个应用的state,包含应用中需要统一管理的状态及操作状态相关的动作。每个组件都能读取store中的任何一个state,通过 createStore 方法创建 store 实例

      • store 就是 redux 的一个数据中心,简单的理解就是我们所有的数据都会存放在里面,然后在界面上使用时,从中取出对应的数据。因此最开始,我们要创建一个这样的 store,redux提供了createStore方法。
      • Store 有以下职责:
        1.createStore 可以帮助我们创建一个store
        2.store.dispatch 帮助我们派发 action 这个 action 会传递给 store
        3.store.getState 获取到 store 里面所有的数据内容
        4.store.subscribe 可以让我们订阅(监听) store 的改变,只要 store 发生改变, 这个方法的回调函数就会执行
    • 2.state:状态,是全局范围内需要共享管理的组件间数据。

    • 3.action:用来描述发生了什么,它是一个 JavaScript 对象,通常有两个属性:type、payload。type 指的是动作类型(比如添加、修改、删除),payload 是有效载荷(比如待添加的新待办事项对象、待修改的id、待删除的id)。

    • 4.reducer: 纯函数,是实现状态更新的函数(同步状态更新),把 action 和 state 串起来(在 reducer() 函数中需要传递 state 与 action 参数),在函数主体中实现状态更新的动作,但不是直接在原始 state 上直接修改更新,而是返回更新后新的 state 对象。我们不能直接调用到 reducer() 函数,而是需要 dispatch action 触发它的调用。
      dispatch 函数:用于触发 reducer() 的调用以实现更新 state 的动作。在调用 dispatch() 函数时,传递 action 作为参数。

    • 注:为什么 Redux 中的 reducer 和 vuex 中的 mutation 都是同步的状态更新?

      • 就是为了在开发工具里面好跟踪状态变化,因而把它设计为同步的
      • vuex和redux都是一种状态管理机制。然后他们会有自己的state(状态)和修改state的方法,修改state的方法涉及到同步和异步,vuex的处理方式是同步在mutation里面,异步在actions里面,然后redux的同步就是reducer,异步更多的是用户自己去通过中间件的方式去实现

    4、Redux 使用的三大原则:

    • 1.单一数据源
      整个应用的 state 被储存在一棵 object tree (对象树)中,并且这个 object tree 只存在于唯一一个 store 中。
    • 2.State 是只读的
      唯一改变 state 的方法就是触发(dispatch) action,action 是一个用于描述已发生事件的普通对象。
    • 3.使用 reducer 纯函数来执行修改
      为了描述 action 如何改变 state tree (状态树),需要编写 reducers。

    5、绑定库 react-redux

    Redux 与 React 没有任何的关系,redux 可用于其它库或框架中实现状态管理,甚至原生 js 中都能直接使用 redux 实现状态管理,只是 redux 结合 react 使用体验最好。

    react 中要使用 redux 来实现状态管理,需要安装 react-redux 绑定库。

    $ npm i react-redux
    # 或
    $ yarn add react-redux
    

    Provider:组件,用于保存 store,以便所有 <Provider> 后代组件可以连接使用 store

    connect(mapStateToProps, mapDispatchToProps):用于连接视图组件和 store

    • mapStateToProps :这个函数接收的参数必须是一个Function,作用是把 state 绑定到 props 上

      • 传递 state 参数,返回一个对象,用于将 store 中 state 对象中的数据连接到组件中,并合并到组件的 props 中,以便组件使用
      • 如果定义了 mapStateToProps 参数,组件将会监听 Redux store 的变化。任何时候,只要 Redux store 发生改变,mapStateToProps 函数就会被调用。从而更新组件的 state ,state 更新,props 就会更新,从而使整个页面进行更新。
    • mapDispatchToProps :这个函数接收的参数可以是一个Function,也可以是Object,它的作用是将 action creator 函数合并到组件的 props 中。

      • 如果传递的是一个对象,那么每个定义在该对象的函数都将被当作Redux action creator,而且这个对象会与 Reduxstore 绑定在一起,其中所定义的方法名将作为属性名,合并到组件的 props 中;
      • 如果传递的是一个函数,该函数将接收一个 dispatch 函数,然后由你来决定如何返回一个对象,这个对象通过 dispatch 函数与 action creator 以某种方式绑定在一起
    • connect() 返回的是高阶组件(高阶函数)

    6、Redux工作流程:

    1.视图组件在 redux 中派发 action 方法
    2.action 通过 store 的 dispatch 方法派发给 store
    3.store 接收 action,连同之前的 state,一起传递给 reducer ,reducer 实现更新 state 的动作后返回新的 state 给 store
    4.store 去改变自己的 state
    5.视图组件连接了 store ,store 中的 state 更改后,视图组件的数据也就随之更改从而重新渲染页面。
    在这里插入图片描述
    上图展示了redux数据的基本流程,简单的说就是view dispatch一个action后,通过对应reducer处理,然后更新store,最终views根据store数据的改变重新渲染界面。

    7、redux 使用案例一

    • 注:这个案例参考 shopping-cart 项目文件,且这个案例使用的是同步 action
    • 1.action:它是用来描述行为的,即描述要进行怎样的操作,比如增删改查,为每一个行为定义一个唯一的 type 值 — 可把这个给行为定义 type 属性的操作单独提取为一个文件,比如 action-type.js
    // 添加购物车项
    export const ADD_CART_ITEM = Symbol('ADD_CART_ITEM')
    
    // 移除购物车项
    export const REMOVE_CART_ITEM = Symbol('REMOVE_CART_ITEM')
    
    • 2.定义 action creator 创建函数,比如在购物车组件中要对商品进行加入和移除的操作,那么在 actions 目录下建一 cart.js 文件,在这个文件中定义两个 action creator 创建函数,两个创建函数分别用来描述加入的行为和移除的行为。在该文件中要引入描述这两个行为的 type 值文件。然后在 action creator 创建函数里返回一个 action 对象,这个对象有两个属性,一个是 type,一个是 payload 有效载荷,有效载荷就是在 dispatch action 后触发 reducer 时需要携带的参数,比如商品的 id 后者是其他的数据。
    /* 定义 action create 函数 (用于生成 action 对象) */
    
    import { ADD_CART_ITEM, REMOVE_CART_ITEM } from "./action-type"
    
    // 生成加入购物车项的 action 对象
    export const addCartItemAction = item => {
      return {
        type: ADD_CART_ITEM,
        payload: {
          ...item,
          checked: true
        }
      }
    }
    
    // 生成移除购物车项的 action 对象
    export const removeCartItemAction = id => ({
      type: REMOVE_CART_ITEM,
      payload: id
    })
    
    • 3.reducer:这是一个纯函数,它接收两个参数,第一个是旧的 state,第二个是 action 对象,然后根据 action 对象中不同的 type 值来做判断,确定执行怎样的修改 state 的操作,实现 state 的修改操作后,返回一个新的 state 给 store 。
    // 购物车的 reducer 
    // 使用 rxre 回车可以直接把 reducer 的结构建立起来
    
    import { ADD_CART_ITEM, REMOVE_CART_ITEM } from "../actions/action-type"
    
    const initState = {
      cart: []
    }
    
    /**
     * 实现购物车状态更新
     * @param {*} state 旧的状态(修改前的状态数据)
     * @param {*} action 动作,有 type 与 payload 属性
     * 
     * @returns 返回新的 state 状态对象
     */
    const cartReducer = (state = initState, action) => {
      // 根据 action 的 type 值,判断作何状态更新
      switch (action.type) {
        case ADD_CART_ITEM: // 添加购物车项
          return {
            ...state,
            cart: [
              ...state.cart,
              action.payload
            ]
          }
        case REMOVE_CART_ITEM: // 移除购物车项
        default:
          return {
            ...state,
            cart: state.cart.filter(prod => prod.id !== action.payload)
          }
      }
    
    }
    
    export default cartReducer
    

    当需要创建多个 reducer 时,比如要创建一个购物车的 reducer 和用户信息的 reducer ,那么就用 combineReducers 函数把两个 reducer 合并为一个根 reducer

    // 用户信息的 reducer
    const initialState = {
    
    }
    
    const userReducer = (state = initialState, { type, payload }) => {
      switch (type) {
    
      case 'typeName':
        return { ...state, ...payload }
    
      default:
        return state
      }
    }
    
    export default userReducer
    
    /* 在这个主入口文件里将多个独立 reducer 合并成一个根 reducer */
    import { combineReducers } from 'redux'
    import cartReducer from './cart'
    import userReducer from './user'
    
    export default combineReducers({
      cart: cartReducer,
      user: userReducer
    })
    
    • 4.store:仓库,用 createStore 方法来创建 store 仓库,在 createStore 函数中将根 reducer 作为参数传递进去
    import { createStore } from 'redux'
    
    import rootReducer from '../reducers'
    
    // 调用 createStore 创建 store
    const store = createStore(rootReducer)
    
    export default store
    
    • 5.index.js 文件是整个应用的主入口文件,在该文件中引入 react-redux 绑定库中的 Provider 组件来包裹顶层组件 App,在 Provider 组件的标签中将 store 作为属性传递进去,这样在所有的后代页面组件中都能使用到 store 中的 state
    import React from 'react'
    import ReactDOM from 'react-dom'
    import { Provider } from 'react-redux'
    import App from './App'
    import store from './store'
    
    ReactDOM.render(
      <Provider store={store}>
        <App />
      </Provider>,
      document.getElementById('root')
    )
    
    • 6.页面组件要与 store 连接,还要在页面组件中引入 react-redux 绑定库中的 connect 函数,它在被调用后返回的是一个 HOC 高阶组件(高阶组件本质就是一个高阶函数),怎样去使用 connect 函数呢?在页面组件中定义一个变量,比如 hoc ,将 connect 函数赋值给这个变量,由于该函数在调用后返回的是一个高阶组件,所以 hoc 变量此时就是一个高阶组件(高阶函数),在导出页面组件时,就用这个 hoc 变量去包裹页面组件,因为高阶组件接收一个组件作为参数返回一个高阶组件,所以当前的页面组件就变成了一个高阶组件。那么继续来说 connect 函数的使用,它接收 4 个参数,最常用的是第一、二个参数,分别是 mapStateToProps、mapDispatchProps。

      • mapStateToProps 接受一个函数作为参数,它的作用是把 store 中的 state 合并到组件的 props 上,以便组件使用,这样组件就可以通过 this.props.state 来获取到 state 。它接收 state 作为参数,返回一个 state 对象。
      • mapDispatchProps 接收的参数可以是一个函数,也可以是一个对象。它的作用是将 action creator 函数合并到组件的 props 中
    • mapDispatchToProps :可以是一个Function,也可以是Object,作用是绑定action创建函数到props上。如果接收的是一个函数,该函数将接收一个 dispatch 函数作为参数,然后返回一个对象,这个对象通过 dispatch 函数与 action creator 创建函数以某种方式绑定在一起。这个对象里的属性将绑定到组件的 props 中,这个对象里的属性名将作为方法名在该页面组件中使用。组件可以通过 this.props.方法名 来使用。具体怎样去使用这个对象里的方法?比如在购物车组件中,给加入和移除按钮绑定事件,通过绑定的事件去调用这个对象里的方法,并将有效载荷比如 id 作为参数传递到这个方法中,这样就可以在组件中通过绑定的事件去 dispatch action ,进而在 reducer 里对数据进行修改,然后返回一个新的 state 到 store 中,组件接收到更新后的 state 后对页面进行更新操作。

    8、redux 使用案例二

    • 注:这个案例参考 prevention 项目文件,这个案例使用的是异步 action
    • 1.同样的,按照上面的操作,定义 action 的 type ,定义 action creator 创建函数,不同于同步 action 的是,该创建函数返回的不是一个对象,而是一个新函数,返回的这个新函数会被 redux thunk 中间件自动调用执行,所以不用再手动 dispatch action。再返回的新函数中可以执行带副作用的操作,包括执行异步 ajax 请求,以及清理用户数据等操作。redux thunk 中间件在调用该函数时,会传递 dispatch 作为参数,dispatch 函数里的参数是一个对象,这个对象里有两个属性,一个是 type ,一个是 payload。
    export const loginAsync = ({username, password, remember}) => {
      return async dispatch => {
        try {
          // 在该函数中可以执行带副作用的操作,包括执行异步 ajax 请求
          const result = await login ({username, password})
          // 用户登录成功后,算出其能访问到的路由数组
          const menus = generateAccessRoutes(result.menus)
          // result 中保存用户登录成功的数据
          // 执行状态更新:dispatch(action)
          dispatch({
            type: LOGIN_SUCCESS,
            payload: { // 这个 result 就是后端保存的用户的数据信息
              ...result,
              menus
            }
          })
          // 数据持久化
          // 如果勾选了记住用户就用 localStorage 来存用户登录状态,没勾选就用 sessionStorage 来存
          const storage = remember ? localStorage : sessionStorage
          storage.setItem('username', result.username)
          storage.setItem('avatarUrl', result.avatarUrl)
          storage.setItem('token', result.token)
        } catch (e) {
          message.error('用户名或密码错误')
        }
      }
    }
    
    • 2.创建 reducer
    • 3.创建 store ,在该文件中引入 redux-thunk 中间件,这是用于处理异步 action 的中间件,还要引入 redux-logger ,用于打印 action 日志,此时用 createStore 创建 store 时要传入两个参数,第一个还是根 reducer ,第二个是 applyMiddleware 函数,这个函数里接收两个参数,第一个是 redux-thunk ,第二个是 redux-logger
    import { createStore, applyMiddleware } from 'redux'
    import thunk from 'redux-thunk' // 用于处理异步 action 的中间件
    import logger from 'redux-logger' // 用于打印 action 日志
    import rootReducer from '../reducers'
    
    // 根据根 reducer 创建 store 对象(仓库)
    export default createStore(rootReducer, applyMiddleware(thunk, logger))
    
    • 4.在 index.js 主入口文件中用 Provider 组件包裹后代组件,标签中传入 store
    • 5.用 connect 连接组件与 store 。注意:在 class 组件中用 connect 时可以用上个案例的写法,也可以用注解式写法,不用专门定义一个变量来接收 connect 返回的高阶组件,它会自动的把页面组件作为它返回值的那个高阶函数的参数传递进去,就是自动将当前页面组件转换成了高阶组件。另外, connect 的第二个参数返回的不是一个函数,而是一个对象,对象的属性值就是 action creator 创建函数,比如处理登录请求的创建函数,它传递到组件中作为方法被组件调用。
    • 6.用了 redux thunk 中间件后就不需要手动的 dispatch action,那么它是如何操作的呢?
      以登录为例:在登录组件中,点击登录按钮,就会触发 login 方法的调用,而这个方法其实就是处理登录的那个 action creator 创建函数,通过调用这个创建函数,在该函数中,登录成功就会 dispatch 成功的 action ,最终会触发 reducer 纯函数的调用,reducer 会返回一个新的 state ,新的 state 里就把从后端获取的用户数据,包括用户名、头像、token 等合并进去,state 更新后,会导致 mapStateToProps 函数的调用,组件将会获得更新的 state ,从而更新页面。
    展开全文
  • redux原理

    2019-10-23 20:00:00
    redux原理解析 redux状态管理库向外暴露了六个API: createStore, combineReducers, applyMiddleware, bindActionCreators, componse,今天就来尝试通过手写其中的几个Api,来更加了解redux的工作机制 createStore 这...

    redux原理解析

    redux状态管理库向外暴露了六个API: createStore, combineReducers, applyMiddleware, bindActionCreators, componse,今天就来尝试通过手写其中的几个Api,来更加了解redux的工作机制

    createStore

    这个createStore是用来创建store对象的,用于保存状态树中的数据,且是唯一一个,createStore向外暴露了三个方法:getState(), subscribe, dispatch,那就赶紧动手来实现吧

    export const createStore =  (reducers, enhance) =>  {
    	let state = {}; // 状态数据
    	let listeners = []; // 收集listener
    	if (enhance) {
    		return enhance(createStore)(reducers); //返回增强后的store
    	}
    	const getState = () => { //获取store中的state数据的方法
    		return state;
    	};
    	const subscribe = (listener) => { // 变化监听器,每次dispatch的时候,都会去执行这个listener函数
    		listeners.push(listener);
    	}
    	
    	const dispatch = (action) => {  // 分发action,执行reducer操作,产生新的state数据
    		state = reducer(state, action);
    		listeners.forEach(l => l());
    	}
    	dispatch({type:'@INIT-REDUX'}); // 分发一个初始化的action
    	return {getState, subscribe, dispatch};
    }
    

    applyMiddleware(…middleware)

    使用middleware的自定义方法来扩展redux, applyMiddleware可以让你包装store中的dispatch方法来达到你想要的目标,比如能够dispatch一个函数,能够处理异步操作

    applyMiddleware(loggge, jdeid)
    export const applyMiddleware = (...middlewares) => {
    	return createStore => (...reducers) => {
    		const store = createStore(...reducers);
    		let dispatch = store.dispatch
    		let middlewareApi = {
    			getState: store.getState,
    			dispatch: (...args) => dispatch(...args)
    		};
    		// 将多个middleware组成一个调用链,每个middleware接收两个参数:真实store的dispatch和getState方法调用链的最后一个接收真实store的diapatch方法作为参数,借此结束调用链
    		middlewareChain = middlewares.map(middleware => middleware(middlewareApi) );
    		// 增强store的dispatch方法
    		dispatch = compose(...middlewareChain)(dispatch);
    		return {
    			...store,
    			dispatch
    		}
    	}
    }
    

    componse

    从左到右组合多个函数,将多个函数组合成一个函数

    export const componse = (...fns) => {
    	if (fns.length === 0) {
    		return fn => fn
    	} else (fns.length === 1) {
    		return fns[0];
    	} else {
    		fns.reduce((prev, item) => (...args) => prev(item(...args)))
    	}
    } 
    

    bindActionCreators

    使用dispatch对每个action creator进行包装。以便后续直接调用

    const bindActionCreator = (creator, dispatch) => {
    	return (...args) => dispatch(creator(...args))
    }
    
    const bindActionCreator = (creators, dispatch) => {
    	Object.keys(creators).reduce((ret, item) => {
    		ret[item] = bindActionCreator(creators[item], dispatch);
    		return ret
    	}, {})
    }
    
    展开全文
  • redux原理实现

    千次阅读 2019-06-09 23:24:24
    redux原理实现 在明白redux的原理之前,我们需要知道的就是redux的作用。redux其实就是根据react封装的一个库,其解决的问题就是处理异步数据。其基本思想就是将所有的数据与有关与数据的操作都放在store当中,...

                                                                                  redux原理实现

        在明白redux的原理之前,我们需要知道的就是redux的作用。redux其实就是根据react封装的一个库,其解决的问题就是处理异步数据。其基本思想就是将所有的数据与有关与数据的操作都放在store当中,那么为什么要这样做的原因是什么呢?相信大家在直接使用react的时候,会有两个很大的问题,第一就是数据之间的传递过程,一般的情况下我们通常采用的方式就是逐级传递,第二数据之间的影响问题,如果我们每个组件中都存放数据,而在实际的过程中,如果项目足够大,有时候很多的时候都不能够分清各个数据之间的关系,这种情况可能会使得我们开发项目遇到很多难以发现的问题。

    对于redux,首先需要明白的是其核心的几个概念就是store.getState(),store.dispatch(),store.subscribe(),createStore,reducer,action与react-redux中的connect。他们之间的各个部分的功能主要是

      store.getState()其功能是将放在store的数据取出;

      store.dispatch()其功能是告诉store,用户这边发生了什么要求数据更加的行为;

      reducer其功能是去执行数据更改的行为;

      store.subscribe()其功能是检测数据是否发生变化;

      createStore()其接受reducer这个更改了数据之后state,然后再在createStore中执行各种操作,返回新的数据内容到store中;

      action其功能是用户请求的表达着,表达用户要进行什么样的操作。

    明白了上面的内容后我们就来进行redux原理的正式实现

    1.抽离store,将state与dispatch结合在一起,并且将其命名为store,然后再去构建一个函数createStore其目的就是专门用于生产state与dispatch

    createStore里面有两个参数,第一个参数表示应用程序的状态,第二个是stateChanger用来描述会更具action来发生什么样子的变化

    2.监控数据发生变化,在上面创建的createStore中第二个参数stateChanger就是去监控数据发生的变化,但是有个缺点就是之前写的方法需要手动的去更新,显然在实际的开发过程中,这种方式显然是不可取的。因此需要在stateChanger内部去添加这种制动更新的过程

    要达到上面所说的自动更新还需要一个操作,那就是你要实时的去检测到这种变化,并且实时的更新数据,这个时候就使用store.subscript(listener)来实现这样的目的。

    3.纯函数与共享性能提升

    为什么会使用纯函数?在接触redux中的reducer中接触到的一个重要概念就是纯函数,为什么ruducer是一个纯函数呢,那就是因为我们想要达到一个效果,那就是接受一个state并且返回一个新的state,然后再将新的state存放到store当中。如果不采用纯函数,那样会造成的一个后果就是如果在你之前存入的数据中有可变的因素,那么在下一次你需要去使用里面的数据时,就会发生很多问题。

    共享性能的提升,我们需要做到一个目的,那就是每次更新数据的时候,不需要去每次都去重新渲染整个页面的内容,只需要我们修改数据更改之后的数据。这样的好处是不言而喻的,能很明显的提高运行的速度,使最终的产品能够达到高效的过程。因此在对于stateChanger时,应使用下面的这种共享性能。

    4.真正的reducer,其需要达到的目的是既能获取初始化数据的功能,又能生成更新后的数据,因此就有了下面的这段代码的产生。

    5.最终版本的createStore,既然之前的reducer原理已经清楚明了,那么createStore就应该对reducer做出更加正确的反应。因而就得到了其最终的代码的原理

    6.react-redux中connect原理的实现,其实connect的原理很简单,就是高级组件与context后而写成的,其功能是实现异步数据之间的传递。那么首先我们来实现一下只有一个mapStateToProps参数形式的connect,其代码如下

    上面形式显然在实际的过程中是不可取的,因为此种方式去连接state是不准确的,因为...stateProps只反应有状态组件中的数据连接方式,其二是获取更新数据,每一次执行用于不同的操作时,要自动的去渲染并且连接到实时的数据。因此在这里我们采用下面的这种形式

    显然这样的connect是不合理的,因为这里你连接的只是state,关于异步数据之间的操作并没有进行连接,因此在此时我们需要重新的再去更新connect的写法

    上面的部分就是关于如何去使用react去实现redux的全部内容,讲到这里就非常的清楚react与redux之间的关系了,redux就是使用react封装好的一个库,在实际的开发中,我们不需要自己去实现这个过程,可以直接去调用redux,并且使用react-redux中的connect来进行项目的实际开发,这样的好处就是极大的节约了我们开发的时间,这种由官方封装好的库,在远远比我们自己去实现这个更加的强大。

    展开全文

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 8,981
精华内容 3,592
关键字:

redux原理