使用useReducer+useContext打造简版redux

1,451 阅读3分钟

前言 

     大家好, react hooks出来已经有一段时间了, 相信很多热爱钻研新技术的童靴已经对react hooks有了一定的了解, 作者也是抱着发现新大陆的心态去学习并在项目中进行实践, 在这里也是和大家分享一下如何使用useReducer+useContext来实现一个简版redux。

背景

      往往新特性、新技术的诞生是来自于问题的产生, 本篇文章的产生也是为了解决问题。我先前问过领导一个问题, 为什么项目中不使用redux或者mobx来作状态管理哪? 

      大家可以想象一下, 譬如以react为技术栈, 使用redux作为状态管理, 会遇到如下几个问题

(1)需要安装redux、react-redux、react-thunk等依赖, 依赖包变多变杂

(2)我们需要去熟悉createStore、dispatch、mapStateToProps等好多API, 这无疑大大增加了学习成本

(3)redux其实是将一整颗state树配合着方法以props的形式从根节点传递, 传递一层两层还可以, 层级如果多了, 维护起来会很吃力

       既然问题出现了, 就要想着就解决问题, 那么有没有好的替代方案来解决优化上面的问题那, 当然是有的, 下面以一个表格新增删除行数据为例来手把手教大家如何使用useReducer+useContext来打造一个简版的状态管理库。[完整demo]

实践

index.js(核心代码)

useReducer

  • 传递两个参数, 第一个参数是更改state状态的方法, 类似于redux的reduce, 第二个参数是初始化状态
  • 返回两个参数,第一个参数为更改后的状态, 第二个参数是dispatch(用来触发更新state的操作, 类似于redux中store的dispatch)

useReducer会在页面初始化时执行一次, 此时使用到的是初始状态, 当状态更新时, 使用的是返回的dataSource, 并重新渲染

 context

  • 使用React.createContext({})创建context并导出使用
  • 使用context.Provider, 接收一个value属性, 在这个地方可以传递任何数据, 你的dispatch、state亦或者是以对象形式传递多种数据

context的作用是提供了一种在组件之间共享此类值的方式,而不必显式地通过组件树的逐层传递 props。context小知识

reduer.js

目的是统一处理更新state

TableDemo.jsx

...
const { dispatch } = useContext(context);
dispatch({
    type: types.ADD_ROW_DATA,
    payload: {
        key,
        name: 'demo' + key,
        age: 26,
        address: '恒电大厦B座2层',
        email: 'demo@meituan.com',
    }
})
...

useContext

  • 接收导出的context, useContext可以让你在任何组件中引入使用, 这里接收的参数是context实例
  • 需要注意的是, 在项目中context可以是多个嵌套的

总结

使用useReducer+useContext作为状态管理, 你不需要安装额外的包(需要注意的时, react hooks是在 React@16.8新增添的功能, 请注意项目的react版本), 你也可以避免层层传递props,只需要简单地记住个别api便可以实现复杂的状态管理, 是不是很棒, 想尝试的朋友们请参照

完整demo