最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • Redux在React Hook中的使用及其原理

    正文概述 掘金(黄刀小五)   2021-02-25   575

    浅谈Redux

    下面将从what, why, how to 三个方面来说说Redux

    第一问 what 什么是Redux

    将一个web应用拆分成视图层与数据层, Redux就是保存其数据的一个容器, 其本质就是维护一个存储数据的对象.

    • State : 一个存放数据的容器 (一个对象)
    const initState = {
      count: 0,
    }
    
    • Action : 一个 want to do 的过程 (计划要做一个什么样的操作)
      • ActionType是对Action的描述, 也是连接ActionReducer的桥梁
      • 本质上是一个由ActionTypepayload(数据)组成的对象
    export const increaseConstant = 'INCREASE' // ActionType
    
    {
       type: increaseConstant,
       payload,
    }  // Action
    
    • Reducer : 一个 to do 的过程 (执行Action计划的操作)
    case increaseConstant: // 当 ActionType 为 'INCREASE' 时, 执行count++
      return {
        ...state,
        count: payload + 1
      }
    

    第二问 why 为什么要使用Redux

    当你不知道是否需要使用Redux的时候, 那就是不需要使用.

    下面一组动图很好的描述了一个应用程序的开发过程, 及何时需要Redux. 图片来源及原文链接

    • 游戏初期阶段, 数据单向传递, 父传子

    Redux在React Hook中的使用及其原理

    • 游戏进入中期, 开始有少量非父子组件间需要通讯一些数据

    Redux在React Hook中的使用及其原理

    • 游戏进入后期, 开始需要大量的数据通讯

    Redux在React Hook中的使用及其原理

    • 此时, 就是Redux的用武之地了, 使用Redux后流程如下

    Redux在React Hook中的使用及其原理

    第三问 how to 怎么使用Redux

    在说使用方法之前, 我们先来从头到尾模拟一个Redux的过程, 只要理解原理, 使用起来那不是小菜一碟.

    Let's go, come on baby!

    Redux在React Hook中的使用及其原理

    下面我们就用一个简单的计数器的例子来模拟实现一个Redux的过程:

    创建一个count组件

    import React, { useState } from 'react'
    
    const CountItem = (props) => {
      const {
        count,
        increase,
      } = props
    
      return (
        <>
          {count}
          <button onClick={increase}>Count++</button>
        </>
      )
    }
    
    const Count = () => {
      const [count, setCount] = useState(0)
    
      const increase = () => {
        setCount(count + 1)
      }
    
      return (
        <CountItem
          count={count}
          increase={increase}
        />
      )
    }
    
    export default Count
    
    

    这样一个简单的count组件就创建好了, 现在, 我们想把对数据的操作单独封装成一个方法名为dispatch, 传递的参数为一个Action 格式: { type: xxx, payload: xxx }

    封装一个Dispatch函数

    const dispatch = (action) => {
      switch(action.type) {
        case 'INCREASE':
          return action.payload + 1
        default:
          break
      }
    }
    

    改写increase方法

    const increase = () => {
    -  setCount(count + 1)
    +  setCount(dispatch({type: 'INCREASE', payload: count}))
    }
    

    这时, 我们将action对象也抽离出来, 方便复用, 新建action.js.

    action.js => 返回action对象

    const increaseCount = (payload) => {
      return {
        type: 'INCREASE',
        payload
      }
    }
    

    改写increase方法

    const increase = () => {
    -  setCount(dispatch({type: 'INCREASE', payload: count}))
    +  setCount(dispatch(increaseCount(count)))
    }
    

    接下来我们把dispatch中的事件操作抽离到reducer中, 新建reducer.js.

    reducer.js => 进行数据操作

    const reducer = (state, action) => {
      const { type, payload } = action
      switch(type) {
        case 'INCREASE':
          return {
            ...state,
            count: payload + 1
          }
        default:
          return state
      }
    }
    

    改写dispatch函数

    const dispatch = (action) => {
      const state = {
        count,
      }
      
      const newState = reducer(state, action)
    
      return newState
    }
    

    改写increase方法

    const increase = () => {
    -  setCount(dispatch(increaseCount(count)))
    +  setCount(dispatch(increaseCount(count)).count)
    }
    

    接下来, 我们把set方法也拿到dispatch中, 让所有操作都在dispatch中完成.

    继续改造dispatch函数, 增加setter做映射

    const dispatch = (action) => {
      const state = {
        count,
      }
      
    +  const setter = {
    +    count: setCount
    +  }
      
      const newState = reducer(state, action)
      
    +  for (let key in newState) {
    +    setter[key](newState[key])
    +  }
    
    -  return newState
    }
    

    改写increase方法

    const increase = () => {
    -  setCount(dispatch(increaseCount(count)).count)
    +  dispatch(increaseCount(count))
    }
    

    这里我们可以看到, action.type是连接actionreducer的桥梁, 我们可以将actionType定义为常量单独保存.

    在action中增加actionType

    export const increaseConstant = 'INCREASE'
    
    // 替换 action 和 reducer 中的 'INCREASE' 为 increaseConstant
    

    基于现有场景, 如果我们有另一个功能, 而目前的reducer并不能帮助我们很好的把不同的功能划分开来, 我们改造一下reducer, 改造成一个对象, 用对象的key去区分功能.

    改写reducer

    const reducer = {
      count(state, action) {
        const { type, payload } = action
        switch(type) {
          case increaseConstant:
            return payload + 1
          default:
            break
        }
      },
    }
    

    这时我们要遍历reducer, 找到正确的key, 才能让程序正确执行, 我们新建combineReducers.js来完成这步操作.

    combineReducers

    const combineReducers = (reducer) => {
      return (state, action) => {
        let ret = {}
    
        for (let key in reducer) {
          ret[key] = reducer[key](state[key], action)
        }
        
        return {
          ...state,
          ...ret,
        }
      }
    }
    

    继续改下dispatch函数, 使其支持当前格式reducer.

    改写dispatch

    -  const newState = reducer(state, action)
    +  const newState = combineReducers(reducer)(state, action)
    

    至此, 一个redux的实现过程就完成了, 接下来, 我们实际用一用redux. 其实, 当完成上述操作的时候, 怎么用就已经说的差不多了.

    Redux在React Hook中的使用及其原理

    Redux + React 使用

    action, reducer, Count组件同上, Count组件需要简单改写下.

    新建store.js

    import { createStore, combineReducers } from 'redux'
    import reducer from './recuder'
    
    const initState = {
      count: 0,
    }
    
    const store = createStore(
      combineReducers(reducer),
      initState,
    )
    
    export default store
    

    新建app.jsx, 引入store

    import { Provider } from 'react-redux'
    import store from './store'
    
    const App = () => {
      return (
        <Provider store={store}>
          <Count />
        </Provider>
      )
    }
    
    export default App
    

    改写Count组件

    import React from 'react'
    import { connect } from 'react-redux'
    import { increaseCount } from './action'
    
    const CountItem = (props) => {
      const {
        count,
        increase,
      } = props
    
      return (
        <>
          {count}
          <button onClick={increase}>Count++</button>
        </>
      )
    }
    
    const Count = (props) => {
      const {
        count,
        dispatch,
      } = props
    
      const increase = () => {
        dispatch(increaseCount(count))
      }
    
      return <CountItem count={count} increase={increase} />
    }
    
    export default connect(
      (state) => {
        return state
      },
      (dispatch) => {
        return { dispatch }
      }
    )(Count)
    
    

    接下来, 我们改写成hook的写法

    改写Count组件

    import React from 'react'
    - import { connect } from 'react-redux'
    + import { useSelector, useDispatch } from 'react-redux'
    import { increaseCount } from './action'
    
    const CountItem = (props) => {
      const {
        count,
        increase,
      } = props
    
      return (
        <>
          {count}
          <button onClick={increase}>Count++</button>
        </>
      )
    }
    
    const Count = () => {
    -  const {
    -    count,
    -    dispatch,
    -  } = props
      
    +  const count = useSelector(state => state.count)
    +  const dispatch = useDispatch()
    
      const increase = () => {
        dispatch(increaseCount(count))
      }
    
      return <CountItem count={count} increase={increase} />
    }
    
    - export default connect(
    -  (state) => {
    -      return state
    -  },
    -  (dispatch) => {
    -    return { dispatch }
    -  }
    - )(Count)
    
    + export default Count
    
    

    至此, 本篇文章就到此结束了, 大家可以写个复杂一点的组件练习下, 比如todoList, 手动滑稽. 逃了逃了, 我要去timi去了, 我的小伙伴还等我带他上白银呢, 一帮混子, 带不动.

    Redux在React Hook中的使用及其原理


    起源地下载网 » Redux在React Hook中的使用及其原理

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元