Taro 小程序开发大型实战(四):使用 Hooks 版的 Redux 实现应用状态管理(上篇)

Taro 小程序开发大型实战(四):使用 Hooks 版的 Redux 实现应用状态管理(上篇)_第1张图片
欢迎继续阅读《Taro 小程序开发大型实战》系列,前情回顾:

  • 熟悉的 React,熟悉的 Hooks:我们用 React 和 Hooks 实现了一个非常简单的添加帖子的原型
  • 多页面跳转和 Taro UI 组件库:我们用 Taro 自带的路由功能实现了多页面跳转,并用 Taro UI 组件库升级了应用界面
  • 实现微信和支付宝多端登录:实现了微信、支付宝以及普通登录和退出登录

如果你跟着敲到了这里,你一定会发现现在 的状态管理和数据流越来越臃肿,组件状态的更新非常复杂。在这一篇中,我们将开始用 Redux 重构,因为此次重构涉及的改动文件有点多,所以这一步使用 Redux 重构我们分两篇文章来讲解,这篇是上篇。

如果你不熟悉 Redux,推荐阅读我们的《Redux 包教包会》系列教程:

  • Redux 包教包会(一):解救 React 状态危机
  • Redux 包教包会(二):趁热打铁,完全重构
  • Redux 包教包会(三):各司其职,重拾初心

如果你希望直接从这一步开始,请运行以下命令:

git clone -b redux-start https://github.com/tuture-dev/ultra-club.git
cd ultra-club

本文所涉及的源代码都放在了 Github 上,如果您觉得我们写得还不错,希望您能给❤️这篇文章点赞+Github仓库加星❤️哦~

双剑合璧:Hooks + Redux

写到这一步,我们发现状态已经有点多了,而且 src/pages/mine/mine.jsx 文件是众多状态的顶层组件,比如我们的普通登录按钮 src/components/LoginButton/index.jsx 组件和我们的 src/components/Footer/index.jsx 组件,我们通过点击普通登录按钮打开登录弹窗的状态 isOpened 需要在 LoginButton 里面进行操作,然后进而影响到 Footer 组件内的 FloatLayout 弹窗组件,像这种涉及到多个子组件进行通信,我们将状态保存到公共父组件中的方式在 React 中叫做 ”状态提升“。

但是随着状态增多,状态提升的状态也随着增多,导致保存这些状态的父组件会臃肿不堪,而且每次状态的改变需要影响很多中间组件,带来极大的性能开销,这种状态管理的难题我们一般交给专门的状态管理容器 Redux 来做,而让 React 专注于渲染用户界面。

Redux 不仅可以保证状态的可预测性,还能保证状态的变化只和对应的组件相关,不影响到无关的组件,关于 Redux 的详细剖析的实战教程可以参考图雀社区的:Redux 包教包会系列文章。

在这一节中,我们将结合 React Hooks 和 Redux 来重构我们状态管理。

安装依赖

首先我们先来安装使用 Redux 必要的依赖:

$ yarn add redux @tarojs/redux @tarojs/redux-h5  redux-logger
# 或者使用 npm
$ npm install --save redux @tarojs/redux @tarojs/redux-h5 redux-logger

除了我们熟悉的 redux 依赖,以及用来打印 Action 的中间件 redux-logger 外,还有两个额外的包,这是因为在 Taro 中,Redux 原绑定库 react-redux 被替换成了 @tarojs/redux@tarojs/redux-h5,前者用在小程序中,后者用在 H5 页面中,Taro 对原 react-redux 进行了封装并提供了与 react-redux API 几乎一致的包来让开发人员获得更加良好的开发体验。

创建 Redux Store

Redux 的三大核心概念为:Store,Action,Reducers:

  • Store:保存着全局的状态,有着 ”数据的唯一真相来源之称“。
  • Action:发起修改 Store 中保存状态的动作,是修改状态的唯一手段。
  • Reducers:一个个的纯函数,用于响应 Action,对 Store 中的状态进行修改。

好的,复习了一下 Redux 的概念之后,我们马上来创建 Store,Redux 的最佳实践推荐我们在将 Store 保存在 store 文件夹中,我们在 src 文件夹下面创建 store 文件夹,并在其中创建 index.js 来编写我们的 Store:

import {
    createStore, applyMiddleware } from 'redux'
import {
    createLogger } from 'redux-logger'
import rootReducer from '../reducers'

const middlewares = [createLogger()]

export default function configStore() {
   
  const store = createStore(rootReducer, applyMiddleware(...middlewares))
  return store
}

可以看到,我们导出了一个 configureStore 函数,并在其中创建并返回 Store,这里我们用到了 redux-logger 中间件,用于在发起 Action 时,在控制台打印 Action 及其前后 Store 中的保存的状态信息。

这里我们的 createstore 接收两个参数:rootReducerapplyMiddleware(...middlewares)

rootReducer 是响应 actionreducer,这里我们导出了一个 rootReducer,代表组合了所有的 reducer ,我们将在后面 "组合 User 和 Post Reducer“ 中讲到它。

createStore 函数的第二个参数我们使用了 redux 为我们提供的工具函数 applyMiddleware 来在 Redux 中注入需要使用的中间件,因为它接收的参数是 (args1, args2, args3, ..., argsn) 的形式,所以这里我们用了数组展开运算符 ... 来展开 middlewares 数组。

编写 User Reducer

创建完 Store 之后,我们接在来编写 Reducer。回到我们的页面逻辑,我们在底部有两个 Tab 栏,一个为 “首页”,一个为 “我的”,在 ”首页“ 里面主要是展示一列文章和允许添加文章等,在 ”我的“ 里面主要是允许用户进行登录并展示登录信息,所以整体上我们的逻辑有两类,我们分别将其命名为 postuser,接下来我们将创建处理这两类逻辑的 reducers。

Reducer 的逻辑形如 (state, action) => newState,即接收上一步 state 以及修改 state 的动作 action,然后返回修改后的新的 state,它是一个纯函数,意味着我们不能突变的修改 state。

推荐:

newState = { ...state, prop: newValue }

不推荐:

state.prop = newValue

Redux 推荐的最佳实践是创建独立的 reducers 文件夹,在里面保存我们的一个个 reducer 文件。我们在 src 文件夹下创建 reducers 文件夹,在里面创建 user.js 文件,并加入我们的 User Reducer 相应的内容如下:

import {
    SET_LOGIN_INFO, SET_IS_OPENED } from '../constants/'

const INITIAL_STATE = {
   
  avatar: '',
  nickName: '',
  isOpened: false,
}

export default function user(state = INITIAL_STATE, action) {
   
  switch (action.type) {
   
    case 

你可能感兴趣的:(Taro 小程序开发大型实战(四):使用 Hooks 版的 Redux 实现应用状态管理(上篇))