欢迎继续阅读《Taro 小程序开发大型实战》系列,前情回顾:
- 熟悉的 React,熟悉的 Hooks[1]:我们用 React 和 Hooks 实现了一个非常简单的添加帖子的原型
- 多页面跳转和 Taro UI 组件库[2]:我们用 Taro 自带的路由功能实现了多页面跳转,并用 Taro UI 组件库升级了应用界面
- 实现微信和支付宝多端登录[3]:实现了微信、支付宝以及普通登录和退出登录
- 使用 Hooks 版的 Redux 实现大型应用状态管理(上篇)[4]:使用 Hooks 版的 Redux 实现了
user
逻辑的状态管理重构
这是使用 Hooks 版的 Redux 重构状态管理的下篇,在上篇中我们实现了 user
部分 的状态管理的重构,但受限于篇幅,我们还剩下 Footer
组件部分没有重构,在这一篇中,我们将首先实现 Footer
组件的状态管理的重构,接着我们马上来实现 post
逻辑的状态管理的重构。
如果你不熟悉 Redux,推荐阅读我们的《Redux 包教包会》系列教程:
- Redux 包教包会(一):解救 React 状态危机[5]
- Redux 包教包会(二):趁热打铁,完全重构[6]
- Redux 包教包会(三):各司其职,重拾初心[7]
本文所涉及的源代码都放在了 Github[8] 上,如果您觉得我们写得还不错,希望您能给❤️这篇文章点个在看+Github仓库加星❤️哦~
搞定 Footer 的 Redux 化
本来这个小标题我是不想起的,但是因为,是吧,大家上面在没有小标题的情况下看了这么久,可能已经废(累)了,所以我就贴心的加上一个小标题,帮助你定位接下来讲解的重心。
是的接下来,我们要重构 “我的" tab 页面中的下半部分组件 src/components/Footer/index.js
我们遵循自顶向下的方式来重构,首先是 src/components/Logout/index.js
文件,我们打开这个文件,对其中内容作出如下修改:
import Taro, { useState } from '@tarojs/taro'import { AtButton } from 'taro-ui'import { useDispatch } from '@tarojs/redux'import { SET_LOGIN_INFO } from '../../constants'export default function LoginButton(props) {
const [isLogout, setIsLogout] = useState(false) const dispatch = useDispatch() async function handleLogout() {
setIsLogout(true) try {
await Taro.removeStorage({ key: 'userInfo' }) dispatch({
type: SET_LOGIN_INFO, payload: {
avatar: '', nickName: '', }, }) } catch (err) {
console.log('removeStorage ERR: ', err) } setIsLogout(false) } return ( <AtButton type="secondary" full loading={isLogout} onClick={handleLogout}> 退出登录 AtButton> )}
这一步可能是最能体现引入 Redux 进行状态管理带来好处的一步了 -- 我们将之前至上而下的 React 状态管理逻辑压平,使得底层组件可以在自身中就解决响应的状态和逻辑问题。
可以看到,我们上面的文件中主要有五处改动:
- 首先我们从
@tarojs/taro
里面导出useState
Hooks。 - 接着我们将之前在
src/pages/mine/mine.js
中定义的isLogout
状态移动到组件Logout
组件内部来,因为它只和此组件有关系。 - 接着我们用
isLogout
替换在AtButton
里面用到的props.loading
属性。 - 然后,我们考虑将之前按钮点击调用
props.handleLogout
Redux 化,我们将这个点击之后的回调函数handleLogout
在组件内部定义。 - 最后,我们从
@tarojs/redux
中导入useDispatch
Hooks,并在组件中调用成我们需要的dispatch
函数,接着我们在handleLogout
函数中去 dispatch 一个SET_LOGIN_INFO
action 来重置 Store 中的nickName
和avatar
属性。
提示
这里我们在组件内定义的
handleLogout
函数和我们之前在src/pages/mine/mine.js
中定义的类似,只是使用 dispatch action 的方式替换了重置nickName
和avatar
的部分。
搞定完 Logout
组件,接着就是 LoginForm
组件的重构了,让我们快马加鞭,让它也接受 Redux 光环的洗礼吧!
打开 src/components/LoginForm/index.jsx
,对其中的内容作出相应的修改如下:
import Taro, { useState } from '@tarojs/taro'import { View, Form } from '@tarojs/components'import { AtButton, AtImagePicker } from 'taro-ui'import { useDispatch } from '@tarojs/redux'import { SET_LOGIN_INFO, SET_IS_OPENED } from '../../constants'import './index.scss'export default function LoginForm(props) {
// Login Form 登录数据 const [formNickName, setFormNickName] = useState('') const [files, setFiles] = useState([]) const [showAddBtn, setShowAddBtn] = useState(true) const dispatch = useDispatch() function onChange(files) {
if (files.length > 0) {
setShowAddBtn(false) } else {
setShowAddBtn(true) } setFiles(files) } function onImageClick() {
Taro.previewImage({
urls: [props.files[0].url], }) } async function handleSubmit(e) {
e.preventDefault() // 鉴权数据 if (!formNickName || !files.length) {
Taro.atMessage({
type: 'error', message: '您还有内容没有填写!', }) return } setShowAddBtn(true) // 提示登录成功 Taro.atMessage({
type: 'success', message: '恭喜您,登录成功!', }) // 缓存在 storage 里面 const userInfo = { avatar: files[0].url, nickName: formNickName } // 清空表单状态 setFiles([]) setFormNickName('') // 缓存在 storage 里面 await Taro.setStorage({ key: 'userInfo', data: userInfo }) dispatch({ type: SET_LOGIN_INFO, payload: userInfo }) // 关闭弹出层 dispatch({ type: SET_IS_OPENED, payload: { isOpened: false } }) } return ( length={1} mode="scaleToFill" count={1} files={files} showAddBtn={showAddBtn} onImageClick={onImageC