Redux与前端表格施展“组合拳”,实现大屏展示应用的交互增强

news2025/1/16 17:02:18

Redux 是 JavaScript 状态容器,提供可预测化的状态管理。它可以用在 react、angular、vue 等项目中, 但与 react 配合使用更加方便一些。

Redux 原理图如下,可以看到store仓库是Redux的核心,通过维护一个store仓库管理 state。state 是只读的,唯一改变 state 的方法就是组件触发 Action。通过编写Reducers 函数,它会接收先前的 state 和 action,并返回新的 state。

Redux的核心理念就是如何根据这些 action 对象来更新 state,强制使用 action 来描述所有变化带来的好处是你可以清晰地知道应用中到底发生了什么。如果一些东西改变了,你可以知道为什么变化,action 就是描述发生了什么的指示器。

来看一下Redux在大屏展示中具体的使用场景:

下面的截图是一个产品开发中非常常见的大屏展示界面示例。核心的数据源为一组销售数据,上方三个仪表板以及下方的表格组件共享同一个数据源,实现了数据明细显示以及各维度的数据统计。

从图上来看,似乎已经具备了大屏展示的数据显示和统计功能,但是展示的数据是没有办法被编辑和修改的。此时,你可能会收到来自客户的灵魂拷问:

“展示功能已经不错了,但是表格数据可以实时编辑更新吗?”

图中的销售明细数据是用html表格直接显示的,如果要实现编辑,通常的做法是,我们挑选一个前端表格组件,实现编辑的功能。

文末可下载文章代码文件。

将表格添加到你的 React 应用程序
我们要用电子表格替换这个html表格,修改component文件夹中的SalesTable.js,替换其中的table。

<SpreadSheets hostClass={config.hostClass} workbookInitialized={workbookInit}  valueChanged={(e,info) => handleValueChanged(e,info)}>
				<Worksheet name={config.sheetName} dataSource={tableData} autoGenerateColumns={config.autoGenerateColumns}  >
					<Column width={50} dataField='id' headerText="编号"></Column>
					<Column width={200} dataField='client' headerText="客户"></Column>
					<Column width={320} dataField='description' headerText="描述"></Column>
					<Column width={100} dataField='value' headerText="销售额" formatter={config.priceFormatter} resizable="resizable"></Column>
					<Column width={100} dataField='itemCount' headerText="数量"></Column>
					<Column width={100} dataField='soldBy' headerText="销售人员"></Column>
					<Column width={100} dataField='country' headerText="国家"></Column>                   
				</Worksheet>
			</SpreadSheets>

其中,SpreadSheets元素创建了一个电子表格并定义了如何显示数据列。dataSource 属性定义了绑定的数据源,Column 中的dataField 属性告诉该列应该绑定底层数据集的哪个属性。

接下来是js代码部分,

import '@grapecity/spread-sheets-react';
import "@grapecity/spread-sheets/styles/gc.spread.sheets.excel2016colorful.css";
import { SpreadSheets, Worksheet, Column } from '@grapecity/spread-sheets-react';
export const SalesTable = ({ tableData, valueChangedCallback,} ) => {
    const config = {
        sheetName: 'Sales Data',
        hostClass: ' spreadsheet',
        autoGenerateColumns: false,
        width: 200,
        visible: true,
        resizable: true,
        priceFormatter: '$ #.00',
        chartKey: 1
    }

	function handleValueChanged(e, obj) {
		valueChangedCallback(obj.sheet.getDataSource());
	}
	handleValueChanged.bind(this);

	const [_spread, setSpread] = useState({});

	function workbookInit(spread) { 
		setSpread(spread) 
	}
	}

只需很少的代码即可完成。config中的几个数据属性。是绑定到电子表格中的组件的配置选项。workbookInit 方法是在初始化工作表时调用的回调。handleValueChanged是在表格数据发生变化后的回调

重新运行,即可显示电子表格数据:

现在我们用一个完整的电子表格替换了原来的html table,此时可以对表格中的数据做任意的修改编辑,但是在编辑后上方的销售统计结果并不会实时更新,接下来我们就用Redux来创建一个store仓库用来存储销售数据,以实现数据的共享和实时更新。

将 Redux 添加到你的 React 应用程序

1.引入相关库

"@reduxjs/toolkit": "^1.9.1",
"react-redux": "^7.2.0",
"redux": "^4.0.5"

2.通过createSlice创建切片
新建一个js文件,写入下面的代码,通过Redux 提供createSlice方法,我们创建了一个切片,初始化了state,在其中加入了销售明细数据作为recentSales。为reducers添加了两个方法updatesales和importSales,用于在销售明细数据更新或者导入这两种情况时,来同步recentSales。

import {  createSlice } from '@reduxjs/toolkit';
import { recentSalesdata } from "../data/data";
const initialState = {
      recentSales: JSON.parse(JSON.stringify(recentSalesdata)),
      status: 'idle',
    };

export const salesSlice = createSlice({
      name: 'recentSales',
      initialState,
      reducers: {
        importSales: (state,action) => {
          state.recentSales=JSON.parse(JSON.stringify(action.payload));
        },
        updatesales: (state,action) => {
            let sales=state.recentSales;
            let arr=sales.map(function(o){return o.id});
            console.log(arr);
            action.payload.forEach((newsale)=>{
                  if(arr.indexOf(newsale.id)>=0){

                    state.recentSales[arr.indexOf(newsale.id)]=JSON.parse(JSON.stringify(newsale));
                  }
                  else{
                    console.log("add");
                    state.recentSales.push(JSON.parse(JSON.stringify(newsale)));
                  }
              });
          },
        
      },

    });
export const { updatesales,importSales} = salesSlice.actions;
export const recentSales = (state) =>  state.recentSales.recentSales;
export default salesSlice.reducer;

3.创建store
添加store.js文件并加入下面的代码,这里创建的store中加入了刚刚创建的切片器。

import { configureStore }  from '@reduxjs/toolkit';
import recentSalesReducer from '../store/salesSlice';
export const store = configureStore({
      reducer: {
            recentSales: recentSalesReducer,
      },
});

4.在component组件中使用store
在Dashboard.js中,import下面的代码。

import { useSelector, useDispatch } from 'react-redux';
import {
  updatesales,importSales, 
  recentSales
} from '../store/salesSlice';

然后在创建的Dashboard方法体中,再加入下面的代码,其中react-redux 提供的:

  • useSelector用于获取刚刚创建的state中的recentSales。
  • useDispatch用于调用reducer中已经创建的方法来更新recentSales。
const sales = useSelector(recentSales);
const dispatch = useDispatch();
    function handleValueChanged(tableData) {
      dispatch(updatesales(tableData));
    }
    function handleFileImported(newSales) {
      dispatch(importSales(newSales));
    }

对大屏展示面板加入redux做了上述改造后,就达到了销售数据编辑后,数据统计结果同步更新的效果:

动图中可以看到上面三个仪表板显示的内容也同步进行了更新。原因是表格被编辑后,我们同步更新了state中的recentSales。

好了,现在我们已经有了一个可以随着数据变化而实时更新的增强型仪表板。客户的需求顺利完成,但是在演示时,你很可能又会听到客户说出的下面的需求:

“能支持Excel数据的导入导出吗?”

如果您已经开发软件很长时间,您可能不止一次地从最终客户或者产品经理那里听到过这个灵魂拷问。对于非技术人群来说,觉得要求 Excel 导入/导出/展示是一个非常正常且容易实现的需求。

但实际上,这个问题常常让前端开发人员感到束手无策。处理 Excel 文件需要大量工作。即使使用第三方的grid组件,也很难支持导入一个复杂的Excel表格作为数据。

这个问题通过表格可以变得简单,导入和导入都可以直接实现。这也是我们在开始时使用将电子表格作为表格明细数据显示和编辑控件的原因。下面我们为应用加入Excel导入导出功能

导出为Excel文件

将 Excel 导入导出功能添加到工作表很容易。首先,在界面上添加相关的文件输入框和按钮。把它放在电子表格面板的底部,在 SpreadSheets 结束标记之后添加。

	<div className="dashboardRow">
				{/* EXPORT TO EXCEL */}
				<button className="btn btn-primary dashboardButton" 
					onClick={exportSheet}>Export to Excel</button>
				{/* IMPORT FROM EXCEL */}
				<div>
					<b>Import Excel File:</b>
					<div>
						<input type="file" className="fileSelect" 
						onChange={(e) => fileChange(e)} />
					</div>
				</div>
			</div>

接下来添加点击时触发的 exportSheet方法,首先添加并导入下面的包,其中@grapecity/spread-excelio是SpreadJS中用于导入导出Excel的包。

import { IO } from "@grapecity/spread-excelio";
import { saveAs } from 'file-saver';

然后将导出方法 exportSheet 添加到组件中:

function exportSheet() {
		const spread = _spread;
		const fileName = "SalesData.xlsx";
		const sheet = spread.getSheet(0);
		const excelIO = new IO();
		const json = JSON.stringify(spread.toJSON({ 
			includeBindingSource: true,
			columnHeadersAsFrozenRows: true,
		}));
		excelIO.save(json, (blob) => {
			saveAs(blob, fileName);
		}, function (e) {  
			alert(e);  
		});     
	}

运行测试点击按钮,即可直接获取到导出的Excel文件。
需要注意的是,我们设置了两个序列化选项:includeBindingSource 和 columnHeadersAsFrozenRows。以确保绑定到工作表的数据被正确导出,且工作表包含列标题,

Excel 数据导入

我们继续来添加导入的方法,刚刚创建文件输入框,我们来处理它的onChange事件,创建一个fileChange方法

	function fileChange(e) {
		if (_spread) {
			const fileDom = e.target || e.srcElement;
			const excelIO = new IO();
			const spread = _spread;
			const deserializationOptions = {
				frozenRowsAsColumnHeaders: true
			};
			excelIO.open(fileDom.files[0], (data) => {
				const newSalesData = extractSheetData(data);
				
				spread.getSheet(0).setDataSource(newSalesData,false);
				fileImportedCallback(newSalesData);
			});
		}
	}

选择文件后,使用ExcelIO 导入它。获取其中的json数据。传入自定义的函数extractSheetData,从中提取需要的数据,然后设置给SpreadJS作为电子表格数据源,另外传给fileImportedCallback方法,这个函数中会调用dispatch(importSales(newSales)); 来同步更新了state中的recentSales。

extractSheetData 函数可以在 src/util.util.js 文件中找到,用于 解析Excel中的数据。extractSheetData函数假定导入工作表中的数据与原始数据集具有相同的列。如果有人上传的电子表格不符合此要求,将无法解析。这个应该是大多数客户可以接受的限制。数据不符时,也可以尝试给客户一个提示信息。

Excel导入导出效果

最终的项目可以参考下面的附件
https://gcdn.grapecity.com.cn/forum.php?mod=attachment&aid=MjUzNTE4fGU5MTk4OGQxfDE2NzM0MTYxMjd8NjI2NzZ8OTk3MTg%3D

React、Redux 和 电子表格的配合使用让这个应用的增强开发变的非常方便。借助 Redux提供的可预测化的状态管理和交互式电子表格,可以在很短内创建复杂的企业 JavaScript 应用程序。

拓展阅读

React + Springboot + Quartz,从0实现Excel报表自动化

电子表格也能做购物车?简单三步就能实现

使用纯前端类Excel表格控件SpreadJS构建企业现金流量表
加粗样式

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

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

相关文章

JS严格模式(use strict)

javascript语法不够严谨&#xff0c;例如我们在项目中不用关键字去定义了一个变量a&#xff0c;控制台一切正常。b123;console.log(b)但是&#xff0c;如果开启了严格模式呢&#xff1f;"use strict" b123; console.log(b)此时将会报错Uncaught ReferenceError: b is…

开关电源中功率电感均方根电流是如何推导的?来自《开关电源宝典》

3.2.8 功率电感的有效电流参考“1.7.3 功率电感”章节内容&#xff0c;我们知道&#xff0c;功率电感具有温升电流、RMS电流、饱和电流、额定电流等电流参数。在后续“第5章 降压电路的应用方法”应用实例中进行功率电感选型时&#xff0c;需要保证所选电感的额定电流参数大于实…

自定义类型:结构体,枚举,联合(1)

tips 1. 2. 结构基础知识复习 1. 结构是一些值的集合&#xff0c;这些值被称为成员变量&#xff0c;结构的每个成员可以是不同类型的变量。 2. 结构体类型&#xff0c;结构体成员&#xff0c;结构体变量&#xff0c;结构体指针的创建方式 3. 初始化结构体变量的时候&…

华为开源自研AI框架昇思MindSpore应用实践:FGSM网络对抗攻击

目录一、环境准备1.进入ModelArts官网2.使用CodeLab体验Notebook实例二、对抗样本定义三、攻击方法快速梯度符号攻击&#xff08;FGSM&#xff09;四、数据处理五、训练LeNet网络六、实现FGSM七、运行攻击近年来随着数据、计算能力、理论的不断发展演进&#xff0c;深度学习在图…

老板要求总部-分部异地组网,作为IT运维怎样才能避免踩坑?

最近在开年会&#xff0c;老板提出2023年要全面搭建30个分公司的广域网架构&#xff0c;总部和分公司网络实现统一管理。但是公司原有网络架构复杂&#xff0c;各分支又是不同运营商接入的现状&#xff0c;想要实现异地组网并不容易&#xff01;然而&#xff0c;老板还不断提出…

好用的基于vue的组织架构图组件

都是基于vue的组织架构图&#xff0c;有支持vue2.x和vue3.x,可自行选择使用 一、vue-okr-tree&#xff08;支持vue2&#xff09; 文档地址&#xff1a;vue2-okr-tree 这个文档里面只有使用方法&#xff0c;不像vue3-tree-org里面有详细的介绍和安装引入教程 1.安装与引入 n…

第一章 spring框架概述

1.Spring框架概述*Spring是轻量级的开源的JavaEE框架*可以解决企业应用开发的复杂性*有两个核心的部分&#xff1a;IOC、AOPIOC&#xff1a;控制反转&#xff0c;把创建对象的过程交给Spring进行管理AOP&#xff1a;面向切面&#xff0c;不修改源代码的情况下进行功能的增加*Sp…

ThreadLocal与nheritableThreadLocal的区别及使用

ThreadLocal 多线程环境中&#xff0c;共享变量的并发修改常常导致线程同步问题&#xff0c;ThreadLocal可以存储线程私有的本地变量&#xff0c;从而使线程之间的变量相互隔离 因为ThreadLocal在线程执行的上下文可以传递变量的特性&#xff0c;所以可以很好的解决变量值传递…

PostgreSQL11 | pgsql建表、改表与删表

上一篇文章 PostgreSQL11 | pgadmin4基本使用http://t.csdn.cn/PKpde已经讲解了最简单的pgadmin的数据库创建、外键等可视化的操作&#xff0c;以及对应的pgsql语句 这一篇文章将讲解基础的pgsql语句 建表、改表与删表 目录 建表、改表与删表 创建数据表 单字段主键 多…

12.0、VMware-Linux部署springboot项目(图文超详细教程)

12.0、VMware-Linux部署springboot项目&#xff08;图文超详细教程&#xff09; 第一步&#xff1a;启动 Linux 进入 root 用户&#xff0c;打开终端 输入以下命令 -> 查看 Linux 中是否已经装有 jdk &#xff1b; java -version 1.如果有&#xff0c;需要先将原来的 jdk …

ESP-IDF:使用multimap和vector容器给新员工随机分配部门并按照部门打印

例程&#xff1a; /* 创建5个员工&#xff0c;给5个员工随机分配部门&#xff0c;然后按照部门打印员工*/ #include #include #include #include <time.h> #define SALEDEPARTMENT 1 #define RDDEPARTMENT 2 #define MEDEPARTMENT 3 class worker { public: string …

10分钟做好 Bootstrap Blazor 的表格组件导出 Excel/Word/Html/Pdf

上篇: Bootstrap Blazor 实战 通用导入导出服务(Table组件) 1.新建工程 新建工程b14table dotnet new blazorserver -o b14table将项目添加到解决方案中&#xff1a; dotnet sln add b14table/b14table.csproj使用 nuget.org 进行 BootstrapBlazor 组件安装, FreeSql sqlite…

在线阅读网站|基于Springboot+Vue开发实现小说阅读网站

作者主页&#xff1a;编程指南针 作者简介&#xff1a;Java领域优质创作者、CSDN博客专家 、掘金特邀作者、多年架构师设计经验、腾讯课堂常驻讲师 主要内容&#xff1a;Java项目、毕业设计、简历模板、学习资料、面试题库、技术互助 收藏点赞不迷路 关注作者有好处 文末获取源…

探索SpringMVC-HandlerAdapter之RequestMappingHandlerAdapter

前言 在RequestMappingHandlerAdapter的第一篇文章《探索SpringMVC-HandlerAdapter之RequestMappingHandlerAdapter-参数解析》我们从方法调用的角度提出了三个问题。前面两篇分别回答了方法入参、返回值处理这两个问题。而第三个问题则是由异常处理器负责的&#xff0c;不属于…

栈的讲解及实现(图解+代码/C语言)

今天为大家分享的是栈的模拟实现&#xff0c;本文主要讲解如何以数组的形式模拟实现&#xff0c;同时给出链表模拟实现栈的代码。 目录 图解栈的结构数组模拟栈的分步实现 创建并初始化入栈检测栈是否为空出栈获取栈顶元素获取栈内有效元素个数销毁栈 链表模拟实现栈 模拟思…

学习笔记:统计建模方法的比较分析

前言本文介绍了隐马尔可夫模型 (HMM)、最大熵马尔可夫模型 (MEMM) 和条件随机场 (CRF) 的比较分析。 HMM、MEMM 和 CRF 是三种流行的统计建模方法&#xff0c;通常应用于模式识别和机器学习问题。 让我们更详细地探讨每种方法。一、隐马尔可夫模型 (HMM)“隐藏”一词象征着只有…

node ~ zip压缩 文件加密

我们知道zip压缩,文件加密都是基于http的,下面我用用node实现着几个功能 zip压缩/解压 let zlib require(zlib); // 核心 let path require(path); let fs require(fs);// 压缩流 将1.txt压缩成1.txt.gz function gzip(source){ //source文件目录let gzip zlib.createGzi…

[Android]View的事件分发机制(源码解析)

目录 1.分发对象-MotionEvent 2.如何传递事件 1.传递流程 2.事件分发的源码解析 3.主要方法&#xff1a; 4.事件传递中listener 5.滑动冲突如何用事件分发处理 1.分发对象-MotionEvent 事件类型有&#xff1a; 1.ACTION_DOWN-----手指刚接触屏幕 2.ACTION_MOVE------手…

ASIC和FPGA,选择哪种设计比较好?

很多人都觉得同样都是写Verilog的&#xff0c;ASIC和FPGA其实并没有什么区别&#xff0c;其实并不是这样。那么ASIC和FPGA&#xff0c;选择哪种设计比较好&#xff1f;接下来IC修真院就来为大家细细分析。 ASIC (Application Specific Integrated Circuit)&#xff0c;即专用集…

盘点:2022年勒索金额超百万美元的攻击事件

1、哥斯达黎加政府 勒索赎金&#xff1a;2000万美元 这是2022年最受关注的攻击事件&#xff0c;因为这是一个国家首次宣布进入“国家紧急状态”以应对勒索软件攻击。调查显示&#xff0c;从4月中旬到5月初&#xff0c;27个政府机构成为第一波攻击活动的目标。国家财政部数TB数…