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构建企业现金流量表

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

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

    Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化. 下图是一个产品开发中非常常见的大屏展示界面 ...

  2. ECharts + Jquery 做大屏展示

    HTML <!doctype html> <html> <head> <meta charset="utf-8"> <meta ...

  3. 数据可视化界面UI设计大屏展示

  4. flex布局构建大屏框架并支持翻页动画、滚动表格功能

      本文将利用flex属性构建大屏可视化界面.界面主要分标题栏.工具栏.数据可视化窗口.其中,翻页动画以及滚动表格功能分别分布在数据可视化界面两侧. 鼠标点击标题,可看到左侧窗口翻转动画: 整体布局效 ...

  5. 从零开始设计数据大屏—基于Vue ZT

    虽然已经决定这个项目用Wyn来做了,但是,了解一下如何从头开始写一个数据大屏还是挺有好玩的. ------------- 为什么要做数据大屏? 现如今的大数据逐渐发挥出了它的力量,并无形的改变着我们的 ...

  6. 基于 HTML5 的工业组态高炉炼铁 3D 大屏可视化

    前言 在大数据盛行的现在,大屏数据可视化也已经成为了一个热门的话题.大屏可视化可以运用在众多领域中,比如工业互联网.医疗.交通.工业控制等等.将各项重要指标数据以图表.各种图形等形式表现在一个页面上, ...

  7. 产品如何进行大屏数据可视化.md

    最近接到一个需求,需要给公司的竞赛平台面对省/校/竞赛进行大屏的可视化话数据展示,闲暇之余对自己最近的工作进行一些总结; 一.数据可视化的定义 数据可视化主要是关于数据_视觉表现形式的科学技术研究 - ...

  8. 使用DataV制作实时销售数据可视化大屏(实验篇)

    课时1:背景介绍 任务说明 ABC是一家销售公司,其客户可以通过网站下单订购该公司经营范围内的商品,并使用信用卡.银行卡.转账等方式付费.付费成功后,ABC公司会根据客户地址依据就近原则选择自己的货仓 ...

  9. 不仅仅是双11大屏—Flink应用场景介绍

    双11大屏 每年天猫双十一购物节,都会有一块巨大的实时作战大屏,展现当前的销售情况. 这种炫酷的页面背后,其实有着非常强大的技术支撑,而这种场景其实就是实时报表分析. 实时报表分析是近年来很多公司采用 ...

  10. 使用rem配置PC端自适应大屏

    效果如下 使得大屏不论在什么宽高比例依然能展示全部数据 安装 npm install -S postcss-pxtorem rem配置思路 原先的rem函数是能解决大部分的问题的,如果展示不全,也可以 ...

随机推荐

  1. 现有一个接口DataOperation定义了排序方法sort(int[])和查找方法search(int[],int),已知类QuickSort的quickSort(int[])方法实现了快速排序算法

    欢迎大家加入我的社区:http://t.csdn.cn/Q52km 社区中不定时发红包 文章目录 1.UML类图 2.源码: 3.优缺点分析 1.UML类图 2.源码: package com.bac ...

  2. 日志处理logging

    前言 什么是日志?有什么作用?日志是跟踪软件运行时所发生的事件的一种方法,简单来说它可以记录某时某刻运行了什么代码,当出现问题时可以方便我们进行定位. 由python内置了一个logging模块,用户 ...

  3. 知识图谱-生物信息学-医学顶刊论文(Bioinformatics-2021)-KG4SL:用于人类癌症综合致死率预测的知识图神经网络

    5.(2021.7.12)Bioinformatics-KG4SL:用于人类癌症综合致死率预测的知识图神经网络 论文标题:KG4SL: knowledge graph neural network f ...

  4. 即兴小探华为开源行业领先大数据虚拟化引擎openLooKeng

    @ 目录 概述 定义 背景 特点 架构 关键技术 应用场景 安装 单台部署 集群部署 命令行接口 连接器 MySQL连接器 ClickHouse连接器 概述 定义 openLooKeng 官网地址 h ...

  5. Python全栈工程师之从网页搭建入门到Flask全栈项目实战(3) - 入门Flask微框架

    1.安装Flask 方式一:使用pip命令安装 pip install flask 方式二:源码安装 python setup.py install 验证 第一个Flask程序 程序解释 参数__na ...

  6. Log4shell漏洞研究及其挖矿案例分析

    本文首发于云影实验室,为本人创作,现转载到个人博客,记录一下. 原文链接:https://mp.weixin.qq.com/s/O2xHr2OEHiga-qTnbWTxQg Apache Log4j是 ...

  7. linux重置密码

    方法一: 进入grub菜单界面 按e键 在linux开头的行按ctrl+e 或者end跳到行尾,输入rd.break 按ctrl+x mount -o remount,rw /sysroot chro ...

  8. Codeforces Round #802 (Div. 2)C. Helping the Nature(差分)

    题目链接 题目大意: 给你一个有n个元素的数组a,你可以通过一下三种操作使数组的每一个值都为0: 选择一个下标i,然后让a[1],a[2]....a[ i ] 都减一; 选择一个下标i,然后让a[i] ...

  9. 👍SpringSecurity单体项目最佳实践

    SpringSecurity单体项目最佳实践 到这里,我们的SpringSecurity就已经完结啦,文章中可能有些地方不能做到全面覆盖,视频教程地址 初始项目地址 完成项目地址 1.搭建环境 建议下 ...

  10. C#11之原始字符串

    最近.NET7.0和C#11相继发布,笔者也是第一时间就用上了C#11,其中C#11的有一个更新能解决困扰我多年的问题,也就是文章的标题原始字符串. 在使用C#11的原始字符串时,发现的一些有意思的东 ...