基于 Redux + TypeScript 实现强类型检查和对 Json 的数据清理

news2024/9/20 17:33:51

基于 Redux + TypeScript 实现强类型检查和对 Json 的数据清理

突然像是打通了任督二脉一样就用了 generics 搞定了之前一直用 any 实现的类型……

关于 Redux 的部分,这里不多赘述,基本的实现都在这里:Redux Toolkit 调用 API 的四种方式 和 async thunk 解决 API 调用的依赖问题。

之前的实现方法是这个:TS 使用自动提示生成对象中的键,不过实现了一下还是稍微麻烦了一些,而且 CRUD 中的 Create 操作比较难(因为缺乏默认值),之后还是换了一种写法。

虽然这里是用的是 react redux,不过因为不涉及到渲染部分,以及 redux 也可以在非 react 项目中使用,所以还是放到 TS 分类中了(x

下面就根据自己的经验和目前写的项目讲一下我自己琢磨出来的实现。

对象的类型定义

这种主要是通过 type or interface 去实现,具体没什么差别啦,不过对于我们来说,数据类型是固定的,没必要修改对应的数据类型,使用 type 就好了。具体用 type 还是 interface,还是具体需求具体分析。

另外 type 的优势就是少打一些字……?

具体实现如下:

export type IPost = {
  body: string;
  // 因为网上数据和项目数据格式不一致,所以这里暂时注释掉
  //   id: number;
  title: string;
  userId: number;
};

// 这个跟 redux 存储状态相关
// export interface IPostModel extends ISimpleDataFormat<IPost> {}
export type IRdmMarketModel = ISimpleDataFormat<IRdmMarket>;

随后定义一个默认值:

export const defaultPost: IPost = {
  body: '',
  id: 0,
  title: '',
  userId: 0,
};

这样就完成了最初的设定。

Redux 的类型配置

Redux 的配置就比较复杂了,这一个也是比较项目相关的部分,下面也会一步步地进行拆解进行实现。

API 传来的数据类型

initialState 还是挺重要的,因为我们的 API 有十几二十多个,每一个的存储类型都是一致的,因此就不可能说将同样的东西 cv 十几二十遍。最终我设计的 Redux 存储格式为:

我们的业务是,后端绝对会返回一个 data 的数组,其中的数据类型大致为:

{
  "data": [
    {
      "type": "",
      "id": 0,
      "attributes": {},
      // 并不一定存在
      "relationships": {}
    }
  ],
  // include 也是外链关系,为relationship所包含的entity,数据类型与data一致
  "includes": {}
}

其中 type 为当前 entity 的名称,attributes 为当前 entity 所包含的属性,relationship 为可能存在的外链,includes 通过 query parameters 调用,为 relationship 中,外链对象的具体数据。

在具体存储的时候,我想把 id 放到 attributes 中,这样转化为数组给 UI 组件时会方便一些。于是,我定义了 ISimpleDataFormat 的类型:

export type IRelationship = {
  data: {
    type: string;
    id: number;
  };
};

// 其实这个用 { [key: string]: IRelationship } 的效果应该也是一样的……?
export type IRelationships = Record<string, IRelationship>;

export type ISimpleDataFormat<T> = {
  attributes: T & { id: string };
  relationships?: IRelationships;
};

relationship 我保存了后端传来的数据格式,一来没有特别的复杂,二来对于 create/update 操作,有的时候需要添加 relationship 进行双重验证和建立外链。

Redux 状态的设定

同样,我也对 Redux 存储的状态进行了标准化。首先它需要有一个 loading 状态,这样可以方便 UI 进行状态的更改,同时提醒用户正在拉去数据。其次需要错误的状态,同样也是为了显示在 UI 上,最后需要分别存储 data 和 included。经过讨论,最终决定以 K-V 对的方法存储数据。

最后的状态定义如下:

// 也可以使用 Record,我之后应该会以 Record 为主,毕竟写起来方便些
export type ReduxDataType<T> = { [key: string]: T };

export type ISliceStateType<T, U> = {
  isLoading: boolean;
  error: null | SerializedError;
  data: ReduxDataType<T>;
  included: ReduxDataType<U>;
};

export const initialSliceState = {
  isLoading: false,
  error: null,
  data: {},
  included: {},
};

其中 included 可能会存在多个不同的外链,不过目前我们只用到了一个,所以用 <T, U>,如果之后 included 出现两个以上的外链,那么……再改叭……

slice 的实现

这里主要讲一个 fetch,其他的操作基本一致,没什么特别大的区别。API 方面的话,就用网上的 dummy API 了:

import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
import { initialSliceState } from '../sliceType';
import { ISimpleDataFormat, ISliceStateType } from '../../../types';
import { pick } from 'lodash';

export type IPost = {
  body: string;
  title: string;
  userId: number;
};

export interface IPostModel extends ISimpleDataFormat<IPost> {}

export const defaultPost: IPost = {
  body: '',
  title: '',
  userId: 0,
};

export const fetchPost = createAsyncThunk('posts/fetch', async () => {
  return fetch('https://jsonplaceholder.typicode.com/posts')
    .then((response) => response.json())
    .then((json) => json);
});

const postSlice = createSlice({
  name: 'rdmMarket',
  initialState: initialSliceState as ISliceStateType<IPostModel, unknown>,
  reducers: {},
  extraReducers(builder) {
    builder.addCase(fetchPost.fulfilled, (state, action) => {
      state.isLoading = false;
      action.payload.forEach((data: IPost & { id: string }) => {
        const id = String(data.id);
        const pickedAttributes = pick(data, Object.keys(defaultPost)) as IPost;

        const model: IPostModel = {
          attributes: {
            id,
            ...pickedAttributes,
          },
        };

        state.data[id] = model;
      });
    });
  },
});

export const postReducer = postSlice.reducer;

效果:

在这里插入图片描述

在这里插入图片描述

这里的数据相对而言比较简单,因此说使用 pick 对 model 的操作好像有些多余。不过对我们项目来说:

  1. 后端会自动生成一堆前端用不到的 key,比如说创建时间、更新时间、创建对象、版本等,这些东西前段用不到,存储在状态里就是占用无谓的空间。我们项目数据量还比较大,有的时候会有十几二十来万的数据(2b 项目,非 2c),所以能做一点优化就做一点优化。
  2. 多余的数据传到后端会被 rejected 掉,所以对数据的过滤是必须的

在这里插入图片描述

如果说一些属性是不需要的,直接在 interface 中删掉,TS 就会自动报错了。


类型检查主要还是防止 typo 以及写代码更方便一些,比如说:

在这里插入图片描述

在这里插入图片描述

我们项目的数据都是强定形的,所以对我们项目来说使用 TS 的优势绝对比使用 JS 多……尤其是有些 entity 会有一百多个 attributes,这时候如果没有一些智能提示或者是类型检查,报错都得掉一堆头发

是的,真的发生过,后来发现就因为是 typo 所以拿不到值……还有就是后端改了一些数据类型,然后前端没有在所有的组件中全部更新,导致有些页面出现问题有些事正常的。也就是那时候我们决定要落实 TS 的实现(虽然到最后只有我一个人在认真想怎么重构,猪队友都在用 any……痛苦……

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/835308.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

路桥隧施工管理平台(BIM+实景+GIS)

引言 中科图新公路工程BIMGIS可视化项目管理平台是一种高效的项目管理工具&#xff0c;通过将BIM技术与3DGIS技术融合&#xff0c;实现了宏观地理信息与微观工程模型的集成显示。 该平台为项目管理提供了直观、准确的三维工程虚拟环境&#xff0c;对主要三维空间对象&#xff…

【Java】springboot框架 粮油质量溯源MES生产加工管理系统源码

粮油质量溯源MES生产加工管理系统源码&#xff0c;实现一物一码&#xff0c;全程追溯&#xff0c;正向追踪&#xff0c;逆向溯源。技术架构&#xff1a;spring bootmybatiseasyuimysql 。 粮油生产质量追溯系统实现种植主体、种植基地、生产计划、压榨、精炼、包装、销售、物料…

智能物流千人俱乐部---正式开启!

经过半年的筹备&#xff0c;【研习社智能物流千人俱乐部】今天起正式对外开放。 会员可以直接互相对接联系。 目前已经有100多家各行业代表&#xff08;用户、甲方&#xff09;加入了千人俱乐部。 行业精英主要来自供应链管理、食品、金融供应链、铁路、精密制造、商超电商、电…

实战:k8s里通过argoCD部署jenkins-2023.7.24(测试成功)

实战&#xff1a;k8s里通过argoCD部署jenkins-2023.7.24(测试成功) 目录 实验环境 操作系统&#xff1a; CentOS8 Linux &#xff08;我本次用centos7.6&#xff09; 内存资源&#xff1a;32GB &#xff08;自己nuc机器32G内存&#xff09; 实验软件版本&#xff1a; 工具名…

MySQL 与MongoDB区别

一、什么是MongoDB呢 ? MongoDB 是由C语言编写的&#xff0c;是一个基于分布式文件存储的开源数据库系统。在高负载的情况下&#xff0c;添加更多的节点&#xff0c;可以保证服务器性能。 MongoDB 旨在为WEB应用提供可扩展的高性能数据存储解决方案。 MongoDB 将数据存储为一…

【高危】Apache NiFi 远程资源检索功能存在命令注入漏洞

漏洞描述 Apache NiFi 是一个开源的数据流处理和自动化工具。 Apache NiFi 1.23.0之前版本中包含使用 HTTP URL 进行远程资源检索的 Processors 和 Controller Services&#xff0c;但是未限制普通身份用户配置此功能。经过身份验证的攻击者可配置恶意的外部资源引用地址&…

现场直击!飞凌嵌入式亮相第13届配电技术应用论坛

2023年8月3日&#xff0c;第十三届配电技术应用论坛在杭州开幕&#xff0c;飞凌嵌入式携多款重量级产品及热门方案亮相本届论坛&#xff0c;展位号A49。 飞凌嵌入式作为专注嵌入式核心控制系统研发、设计和生产的高新技术企业&#xff0c;与来自全国各地的行业伙伴共同分享市场…

打破思维定势,头脑风暴必备的3个模板!

在日常工作和生活中&#xff0c;我们常常陷入思维定势&#xff0c;无法找到新的解决方案或创意。而头脑风暴的好处在于它能够打破这种思维定势&#xff0c;激活我们的创造力和想象力&#xff0c;找到新的思路和解决问题的方法。 借由多人参与的头脑风暴&#xff0c;我们可以集思…

[IDEA]使用idea比较两个jar包的差异

除了一些小工具外&#xff0c;idea自带了jar包比较的功能。 把需要比对的jar包放到任意目录下&#xff0c;然后选中两个需要比较的jar包&#xff0c;右键&#xff0c;选择Compare Archives&#xff0c;然后就可以比较了。 这次疏忽了&#xff0c;每次打包前需要commit界面看一下…

数制与码制

用0和1可以组成二进制数表示是数量的大小&#xff0c;也可以表示对立的两种逻辑状态。数字系统中常用二进制数来表示数值。 在微处理器、计算机和数据通信中&#xff0c;采用十六进制。任意一种格式的数可以在十六、二和十进制之间相互转换。 二进制数有加、减、乘、除四种运算…

常用SQL语句总结

SQL语句 文章目录 SQL语句1 SQL语句简介2 DQL&#xff08;数据查询语句&#xff09;3 DML&#xff08;数据操纵语句&#xff09;4 DDL&#xff08;数据定义语句&#xff09;5 DCL&#xff08;数据控制语句&#xff09;6 TCL&#xff08;事务控制语句&#xff09; 1 SQL语句简介…

【数据结构】二叉树 链式结构的相关问题

本篇文章来详细介绍一下二叉树链式结构经常使用的相关函数&#xff0c;以及相关的的OJ题。 目录 1.前置说明 2.二叉树的遍历 2.1 前序、中序以及后序遍历 2.2 层次遍历 3.节点个数相关函数实现 3.1 二叉树节点个数 3.2 二叉树叶子节点个数 3.3 二叉树第k层节点个数 3…

Crack:CAD Exchanger SDK 3.20 Web Toolkit 应用

在CAD Exchanger SDK 版本 3.20.0中&#xff0c;我们在 Web Toolkit 中包含了绘图、BIM 和 MCAD 查看器的示例&#xff0c;以展示如何使用每个工具可视化数据。这些查看器具有显示不同类型数据的特定功能&#xff0c;允许用户根据自己的需求单独使用它们。我们将继续增强每个查…

HTTP隧道识别与防御:机器学习的解决方案

随着互联网的快速发展&#xff0c;HTTP代理爬虫已成为数据采集的重要工具。然而&#xff0c;随之而来的是恶意爬虫对网络安全和数据隐私的威胁。为了更好地保护网络环境和用户数据&#xff0c;我们进行了基于机器学习的HTTP代理爬虫识别与防御的研究。以增强对HTTP代理爬虫的识…

【云原生】详细学习Docker-Swarm部署搭建和基本使用

个人主页&#xff1a;征服bug-CSDN博客 kubernetes专栏&#xff1a;云原生_征服bug的博客-CSDN博客 目录 Docker-Swarm编排 1.概述 2.docker swarm优点 3.节点类型 4.服务和任务 5.路由网格 6.实践Docker swarm 1.概述 Docker Swarm 是 Docker 的集群管理工具。它将 Doc…

百度智能云“千帆大模型平台”最新升级:接入Llama 2等33个模型!

今年3月&#xff0c;百度智能云推出“千帆大模型平台”。作为全球首个一站式的企业级大模型平台&#xff0c;千帆不但提供包括文心一言在内的大模型服务及第三方大模型服务&#xff0c;还提供大模型开发和应用的整套工具链&#xff0c;能够帮助企业解决大模型开发和应用过程中的…

适配器模式(AdapterPattern)

适配器模式 适配器模式&#xff08;Adapter Pattern&#xff09;是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式&#xff0c;它结合了两个独立接口的功能。 优缺点 优点&#xff1a; 单一职责原则。你可以将接口或数据转换代码从程序主要业务逻辑中分…

硬件产品经理:硬件版本管理必不可少

目录 内容简介 工程变更单 文件夹结构、文件命名约定和部件号 硬件持续集成&#xff08;快速原型设计&#xff09; 结论 推荐学习 相关内容 个人简介 内容简介 今天就来谈谈版本管理这个话题。 在做产品的过程中&#xff1a; 有效的版本控制&#xff0c;以及适当的工…

pdf只读模式改成可编辑模式

pdf文件打开之后是只读模式&#xff0c;这个是因为设置了限制编辑&#xff0c;想要将PDF只读模式改为可编辑模式&#xff0c;我们只需要取消限制编辑就可以了。 不过也有可能是因为有些是阅读、编辑一体的PDF阅读器&#xff0c;这种可能需要我们手动转换一下模式。 取消PDF限…