一文详解ReactNative状态管理rematch使用

目录
  • 引言
  • React 和 rematch 创建Todo List App
    • 创建一个 models.ts 文件
    • 创建一个 todo.ts 文件
    • 使用 rematch 的 init 函数创建 store
    • RematchTodoApp 要创建UI 组件
  • 总结

引言

有同学反馈开发 ReactNative 应用时状态管理不是很明白,接下来几篇文章我们来对比下 React 及 ReactNative 状态管理常用的几种框架的使用和优缺点。

上一篇文章介绍了 redux 的升级版 redux-toolkit 的使用,这篇文章我们来看下社区里比较出名的 redux 的升级库:rematch。

React 和 rematch 创建Todo List App

下面是使用 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 组件里获取状态或者分发行为。

和其他库一样,通过 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 组件

创建 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 里导出的类型 RootState
    const 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 有很大的相似度。

完整代码:github.com/shixinzhang…

以上就是一文详解ReactNative状态管理rematch使用的详细内容,更多关于ReactNative状态管理rematch的资料请关注我们其它相关文章!

(0)

相关推荐

  • React Native可定制底板组件Magic Sheet使用示例

    目录 正文 如何使用它 1.安装并导入 2.基本使用方法 预览 正文 一个React Native组件,通过提供一个强制性的API,可以从应用程序的任何地方(甚至在组件之外)调用,以显示一个完全可定制的底部表单,并能够等待它解决并得到一个响应. 这个库依赖于Gorhom的/bottom-sheet 的模态组件,并接受相同的道具和儿童. 如何使用它 1.安装并导入 # Yarn $ yarn add react-native-magic-sheet # NPM $ npm i react-nati

  • React Native之在Android上添加阴影的实现

    目录 在Android上添加阴影 目前有个方法 总结 在Android上添加阴影 官网中明确表示在react native中阴影的样式属性shadow...都是只支持iOS的,并不支持Android. 目前有个方法 可以让Android有灰色的阴影,但是无法指定Android机上的阴影色值,只能是灰色的默认. elevation:4   这个属性中的4是代表阴影的高度. 且这个属性添加后,不会影响iOS机上的原本的彩色的阴影颜色,只是在Android机上显示的是默认的灰色的阴影. btnView

  • ReactNative 状态管理redux使用详解

    目录 正文 安装和配置开发环境 定义数据结构 然后创建行为处理函数 todoReducer 创建 UI 组件: 正文 有同学反馈开发 ReactNative 应用时状态管理不是很明白,接下来几篇文章我们来对比下 React 及 ReactNative 状态管理常用的几种框架的使用和优缺点. 首先来看下 redux 怎么使用. 以下是使用 React 和 Redux 创建 todo list 的一般过程,完整代码见文章末尾: 安装和配置开发环境 安装 Node.js 和 create-react-

  • ReactNative支付密码输入框实现详解

    目录 正文 hooks版本 正文 项目中需求如果涉及钱包,支付等功能,可以大概率会用到输入密码组件,也算是个常见组件吧. 之前写过一个纯js的开源组件,使用的类的形式,也比较老了,可直接添加npm库到项目中进行使用. hooks版本 最近项目需要,又重新写了一个hooks版本的,现在直接上源码,对于不想添加依赖库的伙伴,可直接复制源码到项目中,直接使用. 'use strict'; import React, {useRef, useState} from 'react'; import {St

  • React Native自定义Android的SSL证书链校验

    目录 前言 HTTPS请求 WebSocket 前言 虽然这次分享的内容解决了本人的实际开发需求,但由于不是专职的Android开发工程师,涉及到的Android相关内容可能会存在错误或者写法不合理,仅供参考,请多多指教. 本文示例基于: React Native - 0.67.3 Android - 10+ 不包括iOS 由于业务原因,需要在生产环境里面使用自签发证书,那自然这个证书是无法通过Android证书链验证的,为此需要自定义校验规则. 本文分为两部分,介绍了对HTTPS请求和WebS

  • ReactNative错误采集原理在Android中实现详解

    目录 引言 1 JS错误 1.1 Error 1.2 常见的错误 SyntaxError:语法错误 ReferenceError:引用错误 TypeError:类型错误 RangeError:边界错误 URIError:URI错误 1.3 自定义错误 2 RN错误处理 2.1 JS部分 2.1.1 MessageQueue 2.1.2 ErrorUtils 2.1.3 ExceptionsManager 2.2 Native部分 2.2.1 ExceptionsManagerModule 2.2

  • 详解Vue3-pinia状态管理

    目录 pinia是什么? 官网 安装命令 使用 pinia是什么? 这个是 vue3 新的状态管理工具,简单来说相当于之前 vuex,它去掉了 Mutations 但是也是支持 vue2 的,尤大推荐.因为其logo像是一个菠萝,所以我们还称呼它为大菠萝. 这个是 vue3 新的状态管理工具,简单来说相当于之前 vuex,它去掉了 Mutations 但是也是支持 vue2 的,尤大推荐.因为其logo像是一个菠萝,所以我们还称呼它为大菠萝. 官网 https://pinia.vuejs.org

  • 详解vuex状态管理模式

    一.前言 本次接受一个BI系统,要求是能够接入数据源-得到数据集-对数据集进行处理-展现为数据的可视化,这一个系统为了接入公司自身的产品,后端技术采用spring boot,前端采用vue+vuex+axios的项目架构方式,vuex作为vue的状态管理,是尤为重要的部分.这里,我将vuex如何运作和使用做一次总结,有错的地方,望多多提点. 二.vuex简单使用 安装vuex cnpm install vuex --save 在src目录下建立文件夹,命名为store,建立index.js 如图

  • 一文详解Pinia和Vuex与两个Vue状态管理模式

    目录 前言 安装 挂载 Vuex Pinia 修改状态 vuex Pinia Pinia解构(storeToRefs) getters Pinia Vuex modules Pinia Vuex 写在最后 前言 Pinia和Vuex一样都是是vue的全局状态管理器.其实Pinia就是Vuex5,只不过为了尊重原作者的贡献就沿用了这个看起来很甜的名字Pinia. 本文将通过Vue3的形式对两者的不同实现方式进行对比,让你在以后工作中无论使用到Pinia还是Vuex的时候都能够游刃有余. 既然我们要

  • 一文详解Electron 电源状态管理

    目录 Electron 电源相关模块 其中 powerMonitor 模块提供的接口 powerSaveBlocker 模块提供的方法 空闲状态监控 电源状态监控 锁屏和解锁 休眠和唤醒 系统行为阻断 Electron 电源相关模块 在 Electron 中有两个模块是跟电源相关的: powerMonitor:用于获取电源相关信息,监听电源相关事件 powerSaveBlocker:用于阻止系统进入睡眠状态 其中 powerMonitor 模块提供的接口 powerSaveBlocker 模块提

  • 一文详解Java线程的6种状态与生命周期

    目录 1.线程状态(生命周期) 2.操作线程状态 2.1.新创建状态(NEW) 2.2.可运行状态(RUNNABLE) 2.3.被阻塞状态(BLOCKED) 2.4.等待唤醒状态(WAITING) 2.5.计时等待状态(TIMED_WAITING) 2.6.终止(TERMINATED) 3.查看线程的6种状态 1.线程状态(生命周期) 一个线程在给定的时间点只能处于一种状态. 线程可以有如下6 种状态: New (新创建):未启动的线程: Runnable (可运行):可运行的线程,需要等待操作

  • 一文详解C++中动态内存管理

    目录 前言 1.C/C++程序的内存开辟 2.C语言中动态内存管理方式:malloc/calloc/realloc/free 2.1malloc.calloc.realloc区别? 3.C++内存管理方式 3.1 new/delete操作内置类型 3.2 new和delete操作自定义类型 3.3new和malloc处理失败 4.operator new与operator delete函数 4.1 operator new与operator delete函数 4.1.1 我们看看operator

  • 一文详解go mod依赖管理详情

    目录 1. go的依赖管理发展 2. go.mod 文件分析 3. go mod依赖下载工具 4. 可能出现的问题汇总 1. go的依赖管理发展 GOPATH 所有的依赖都放置在同一路径下,可以复用下载的依赖,但是当不同项目需要依赖不同版本的依赖时,就很容易出现冲突问题. govendor 解决了依赖库版本不一致的问题,但是不好控制(了解即可) go mod 使用go.mod文件管理以来的版本,通过go get下载依赖 2. go.mod 文件分析 module xx/xx/xx/v2 go 1

  • 一文详解Golang 定时任务库 gron 设计和原理

    目录 cron 简介 gron 定时参数 源码解析 Cron Entry 按照时间排序 新增定时任务 启动和停止 Schedule 扩展性 经典写法-控制退出 结语 cron 简介 在 Unix-like 操作系统中,有一个大家都很熟悉的 cli 工具,它能够来处理定时任务,周期性任务,这就是: cron. 你只需要简单的语法控制就能实现任意[定时]的语义.用法上可以参考一下这个Crontab Guru Editor,做的非常精巧. 简单说,每一个位都代表了一个时间维度,* 代表全集,所以,上面

  • 一文详解 Compose Navigation 的实现原理

    目录 前言 1. 从 Jetpack Navigation 说起 2. 定义导航 3. 导航跳转 4. 保存状态 SaveableStateHolder & rememberSaveable 导航回退时的状态保存 底部导航栏切换时的状态保存 5. 导航转场动画 6. Hilt & Navigation 7. 总结 前言 一个纯 Compose 项目少不了页面导航的支持,而 navigation-compose 几乎是这方面的唯一选择,这也使得它成为 Compose 工程的标配二方库.介绍 

  • 一文详解React Redux使用方法

    目录 一.理解JavaScript纯函数 1.1 纯函数的概念 1.2 副作用概念的理解 1.3 纯函数在函数式编程的重要性 二.Redux的核心思想 2.1 为什么需要 Redux 2.2 Redux的核心概念 2.2.1 store 2.2.2 action 2.2.3 reducer 2.3 Redux的三大原则 2.3.1 单一数据源 2.3.2 State是只读的 2.3.3 使用纯函数来执行修改 2.4 Redux 工作流程 三.Redux基本使用 3.1 创建Store的过程 3.

随机推荐