React/ReactNative 状态管理: rematch 如何使用
有同学反馈开发 ReactNative 应用时状态管理不是很明白,接下来几篇文章我们来对比下 React 及 ReactNative 状态管理常用的几种框架的使用和优缺点。
上一篇文章介绍了 redux 的升级版 redux-toolkit 的使用,这篇文章我们来看下社区里比较出名的 redux 的升级库:rematch。
下面是使用 React 和 rematch 创建一个简单的 Todo List App 的代码示例,完整代码见文章末尾:
- 首先,在命令行中输入以下命令新建一个 React 应用:
npx create-react-app todolist
- 安装 rematch 和 react-redux:
npm install @rematch/core react-redux
- 创建一个 models.ts 文件,在其中继承 rematch 的 Models,定义当前业务的所有 model 类型
import { Models } from "@rematch/core";//导出当前业务的所有 model 的类型
export interface RootModel extends Models<RootModel> {//暂时先空着
}//创建并导出所有 model 的实例
export const models: RootModel = {}
在上面的代码中,RootModel 是当前业务的所有 model 接口。
rematch 中的 model 和 redux-toolkit 的 slice 概念类似,都表示一个业务的初始状态和支持的操作。
- 创建一个 todo.ts 文件,在其中使用 rematch 的 createModel 创建一个 todo 的业务 model:
import { createModel } from "@rematch/core";
import { State, TODO } from "../../module/todo";
import { RootModel } from "./models";const initState : State = {todos: [{text: "zsx clean room, model init data"}]
};//创建一个 model(类似 redux-toolkit 的 slice),包括一个业务的初始状态、状态处理和变更后的影响
//最核心的地方 **
export const todo = createModel<RootModel> () ({name: 'todo',state: initState,//reducers 需要是纯函数:只依赖参数进行计算,不使用外部数据reducers: {//与 toolkit 的 slice 不同,参数直接是 payload,更简单addTodo: (state: State, payload: string) => {//返回新状态return {...state,todos: [...state.todos, {text: payload}]};},deleteTodo: (state: State, payload: string) => {const todos = state.todos.filter((item: TODO, index: number)=> {return item.text !== payload});return {...state,todos}}},
})
从上面的代码中我们可以看到,rematch 中的 model 和 redux-toolkit 的 slice 概念类似,在其中可以指定名称、初始状态 和 reducers。
不同之处:
- rematch 的 reducer,参数是 payload,而不是 action,更加直接
- rematch 的 reducer,必须有返回值,否则会报错!
- rematch 直接导出 createModel 的返回值,不需要分别导出 actions 和 reducer
再次强调一下,rematch 中使用 model 表示某个业务的状态管理,我们刚才通过 createModel 创建的 todo 是一个 model,表示 todo 业务的状态管理。
- 回到第三步创建的 models.ts 文件,把我们刚才创建的 todo 添加到 RootModel 的成员里:
import { Models } from "@rematch/core";
import {todo} from "./todo";//导出当前业务的所有 model 的类型
export interface RootModel extends Models<RootModel> {//这里的名称就是后续调用 dispatch 的名称todo: typeof todo
}//创建并导出所有 model 的实例
export const models: RootModel = {todo: todo}
通过上面的代码,就可以知道,当前所有业务 model 里,有一个叫做“todo” 的 model。
同时,导出的所有 model 的实例 models,也有一个成员 todo,它就是前面通过 createModel 创建的 todo model。
- 使用 rematch 的 init 函数创建 store:
import { init, RematchDispatch, RematchRootState } from "@rematch/core";
import { models, RootModel } from "./model/models";//创建 store,参数就是所有业务的 model
export const store = init({models
})store.subscribe( () => {console.log('store update >>> ' + JSON.stringify(store.getState()))
})store.dispatch.todo.addTodo("add from store")//导出类型,用于业务组件里使用
export type Store = typeof store
export type Dispatch = RematchDispatch<RootModel>
export type RootState = RematchRootState<RootModel>
从上面的代码可以看到,init 函数的参数就是我们上一步导出的所有业务 model 的对象 models。
init 返回的 store 本质上就是 redux 的 store,因此和 redux store 一样,也支持 subscribe 和 dispatch。
创建完 store 以后,我们还需要导出几个类型:Store Dispatch 和 RootState,他们用于在 typescript UI 组件里获取状态或者分发行为。
7.和其他库一样,通过 react-redux 的 Provider 将 store 提供给组件树:
import RematchTodoApp from './rematch/RematchTodoApp';
import { store } from './rematch/store';const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement
);//分发给子元素
root.render(<Provider store={store}><RematchTodoApp/></Provider>
);
RematchTodoApp 是下一步要创建的 UI 组件
8.创建 UI 组件,在其中使用 react-redux 的 useSelector 和 useDispatch 获取状态和分发行为:
import {useState} from "react";
import { useDispatch, useSelector } from "react-redux";
import { TODO } from "../module/todo";
import { Dispatch, RootState } from "./store";//业务通过 useSelector 获取数据;通过 useDispatch 分发
const RematchTodoApp = () => {//和 toolkit 类似,需要根据 model 名称访问数据//参数类型就是 store 里导出的类型const todos = useSelector((state: RootState) => {return state.todo.todos;});//和 toolkit 不同的在于,需要声明类型//同时分发的时候也有些不同const dispatch = useDispatch<Dispatch>();const [text, setText] = useState('');const handleInput = (e: any) => {setText(e.target.value)}const handleAddTodo = () => {// 分发的时候,通过 dispatch.<model name>.<reducer name> 的方式调用,参数就是 payload 的类型//toolkit 里的写法:dispatch(addTodo(text))dispatch.todo.addTodo(text)setText('')}const handleDeleteTodo = (text: string) => {//toolkit 里的写法:dispatch(deleteTodo(text))dispatch.todo.deleteTodo(text)}return (<div style={{display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center'}}><h1>This Is Rematch TODO App.</h1><ul>{todos && todos.map((todo: TODO, index: any) => {return (<li key={index}><span>{todo.text}</span><button style={{marginLeft: '12px'}} onClick={() => handleDeleteTodo(todo.text)}>finish</button></li>)})}</ul><div style={{display: 'flex', flexDirection: 'row'}}><input value={text} onChange={handleInput}/><button style={{marginLeft: '12px'}} onClick={handleAddTodo}>Add Todo</button></div></div>)
}export default RematchTodoApp;
在上面的代码中,我们使用 useSelector 获取当前业务需要的状态,因为拿到的是所有业务的数据,因此需要通过 todo 的业务名称获取到属于 todo 的数据:
//和 toolkit 类似,需要根据 model 名称访问数据//参数类型就是 store 里导出的类型 RootStateconst todos = useSelector((state: RootState) => {return state.todo.todos;});
需要注意的是,state.todo.todos 里的「todo」是我们第五步在 models 里增加 todo model 时 key 的名称。
随后我们使用 useDispatch 获取 dispatch,和 toolkit 不同的在于,需要声明类型:
const dispatch = useDispatch<Dispatch>();const handleAddTodo = () => {// 分发的时候,通过 dispatch.<model name>.<reducer name> 的方式调用,参数就是 payload 的类型//toolkit 里的写法:dispatch(addTodo(text))dispatch.todo.addTodo(text)setText('')}
在分发行为的时候,toolkit 是这样:dispatch(addTodo(text)),rematch 是这样:dispatch.todo.addTodo(text) ,个人感觉 rematch 这种略微好一点,避免了层层嵌套。
总结一下,通过 rematch 管理状态分这几步:
继承 rematch 的 Models,定义当前业务的所有 model 类型
使用 rematch 的 createModel 创建一个 todo 的业务 model,声明初始化状态、reducers
- 每个 reducer 的参数是 state 和 payload,必须有返回值
使用 rematch 的 init 函数创建 store,参数就是所有 model
- 导出 RematchDispatch RematchRootState 和 store 的类型
通过 Provider 分发给组件树
在 UI 组件中使用 react-redux 的 useSelector 和 useDispatch 获取状态和分发行为
可以看到,rematch 和 redux-toolkit 有很大的相似度。
完整代码:https://github.com/shixinzhang/redux-sample/tree/main/src/rematch
React/ReactNative 状态管理: rematch 如何使用相关推荐
- React/ReactNative 状态管理终于懂了!redux redux-toolkit 与 rematch 对比总结
有同学反馈开发 ReactNative 应用时状态管理不是很明白,这个问题我之前刚接触 React 时也遇到过,看了好多文章和视频才终于明白,不得不说,React 及三方库这方面做的有点过于复杂了! ...
- 【视频】React ReduxToolkit状态管理:创建store对象及redux调试工具的安装方法
React ReduxToolkit状态管理:创建store
- react全局状态管理_rxv: 在React中用Vue3的reactivity包实现状态管理。
前言 React的状态管理是一个缤纷繁杂的大世界,光我知道的就不下数十种,其中有最出名immutable阵营的redux,有mutable阵营的mobx,react-easy-state,在hooks ...
- Recoil 是 React 的状态管理库
Recoil 是 React 的状态管理库,因此你需要将 Recoil 安装到 React 项目中才能使用.创建 React 项目最方便且推荐的方式是使用 Create React App: npx ...
- react全局状态管理_react 状态管理的复杂度来源
Ui = f(data) 本来按照这个公式,前端开发应该是非常愉悦的.最近发现有一些复杂度是因为现有的工具造成的,导致上面这个公式并不成立. 如果 data 不是一个浏览器的数据,而是数据库里的数据. ...
- react usecontext_Vue3原理实战运用,我用40行代码把他装进了React做状态管理
前言 vue-next是Vue3的源码仓库,Vue3采用lerna做package的划分,而响应式能力@vue/reactivity被划分到了单独的一个package中. 如果我们想把它集成到Reac ...
- hooks组件封装 react_名符其实的react下一代状态管理器hox
自从 React16 版本发布 Hooks 以来,大家纷纷上车尝鲜.毫无疑问, Hooks 在一定程度上解决了组件间功能和逻辑复用的问题,在组件间的逻辑的封装和复用确实真香,但 Hooks 在数据状态 ...
- 名符其实的react下一代状态管理器hox
前言 自从React16版本发布Hooks以来,大家纷纷上车尝鲜.毫无疑问,Hooks在一定程度上解决了组件间功能和逻辑复用的问题,在组件间的逻辑的封装和复用确实真香,但Hooks在数据状态的共享方法 ...
- React 全局状态管理的 3 种底层机制
现代前端框架都是基于组件的方式来开发页面.按照逻辑关系把页面划分为不同的组件,分别开发不同的组件,然后把它们一层层组装起来,把根组件传入 ReactDOM.render 或者 vue 的 $mount ...
最新文章
- 验证插件——jquery.validate.js
- ubuntu linux的特点,16个新特性,让你爱上Ubuntu 20.04,
- torch的拼接函数_从零开始深度学习Pytorch笔记(13)—— torch.optim
- java实现九九乘法表的输出
- linux 监控网络IO、磁盘、CPU、内存
- redis-full-check
- matlab lyap,Matlab的Lyapunov、Sylvester和Riccati方程的Matlab求解
- 计算机技术在档案管理中的应用,浅谈计算机技术在档案管理中的应用
- 不好的测试实践——软件测试的尽早介入
- 3说明书_BMW新3系说明书上没写的6条信息
- java 循环字符_在Java中从循环结果创建字符串
- Hiho----无间道之并查集
- autoware中pure_pursuit控制和MPC控制解析
- 汇编语言 数据寄存器AX、BX、CX、DX
- 常用的字符串方法大全
- OpenCV—播放AVI视频
- 【测试】功能测试用例设计方法总结
- 科学上网后(关掉VPN)之后无法正常连接网络
- 头条小程序 button组件 设置边框问题
- vscode中编写代码时tab键不能用
热门文章
- 安卓锁屏灭屏加载流程
- 苹果账号被禁用怎么办?
- C++中的动态空间扩充方法
- Windows域控管理—如何使用powershell远程连接服务器
- Android自动换行布局
- ossutil覆盖_查看选项_命令行工具ossutil_常用工具_对象存储 OSS - 阿里云
- AWS入门指南之一:怎样创建免费的AWS账号
- 程序员的江湖 务必掌握这些黑话!
- 合并多个excel的行到一个excel
- 索尼录音笔怎么导出录音内容_追黄宗泽新剧追到了索尼录音笔?没办法,就是便携好用颜值高...