这是上一篇文章的续篇: 为什么在2019年编写React Data Grid
Redux的作用是什么? 有很多答案。 例如,使用不同React组件中的共享数据。 但是您可以将Redux用作操作组件的一种方式。 外观本身很有趣:任何React组件都可以通过Redux控制另一个React组件。
以一个以行和列(数据网格,网格)的形式显示数据的React组件。 她可以管理什么功能? 列和行的组成。 分配。 滚动数据会很好。

例如,某个React组件(某些组件)可以像这样管理网格:
- 显示这些行和列;
- 突出显示该词的出现;
- 选择这样一条线;
- 滚动到某一行。
管理列并不困难。 将列设置放在Redux中就足够了:名称,顺序,宽度,数据映射。 网格将采用这些设置并应用。 数据方法是相同的。
但是,让任务复杂化吧。 假设有很多行。 它们无法一次从服务器下载,也无法一次显示。 因此,需要分段数据加载和分段数据映射。
对于部分显示,我们采用了上一篇文章中描述的虚拟滚动。 并尝试在Redux中进行部分加载和存储。 我们还将使其他组件能够通过Redux操纵下载的数据并滚动位置。
这不是抽象任务,而是我们正在开发的ECM系统中的实际任务:

安排要求。 你想得到什么?
- 这样在滚动时会加载新的数据;
- 以便加载的数据位于Redux中;
- 以便可以从其他组件操纵加载的部分。 通过Redux,添加-删除-修改行,网格拾取了这些更改。
- 从而可以从其他组件控制滚动位置。 通过Redux,滚动到所需的行。
我们将考虑这些任务。
有点题外话: 上一篇文章的虚拟滚动使您可以快速滚动到网格的任何部分。 例如,最后。 网格必须加载数据的最新部分(不包括所有中间部分),以免从服务器拉出数千行。 因此,部分并非总是按顺序加载;可以从列表的不同部分下载它们。
我们选择以下方案来加载和存储数据:

此方案中的网格分为两部分-组件表示和容器。 演示文稿仅处理数据显示-这是视图。 数据以页面显示(上一文章已对此进行了描述)。 容器负责加载数据并与Redux交互。
让我们看一下图中的箭头:
- Presentational不会加载数据,它仅通过回调告诉它缺少要显示的数据。 Presentational不了解Redux,它不执行调度操作,并且不连接到Redux存储库。
- 容器负责加载数据。 调用回调时,此组件将请求发送到服务器。 容器可以请求的数据超过其需要显示的数据,以最大程度地减少对服务器的请求数。
- 服务器发送数据。
- 容器将接收到的数据发送到Redux。 Redux存储所有上传的数据部分,而不仅仅是最后上传的部分。
- 一旦下一个数据进入Redux,容器就会从Redux中提取所有数据。
- 并给他们呈现。 Presentational不需要绘制所有接收到的数据,它仅显示落入视口的内容。 同时,加载的数据和呈现的页面不是同一件事。 可以在一个块中装入1000条记录,并在两页中显示50条记录。
这是该电路的伪代码:
class GridContainer extends React.Component<Props> { props: Props; render(): React.Element<any> { return <Grid // . dataSource={this.props.data} // Callback . loadData={this.props.loadData} />; } }
const mapStateToProps = (state) => { return { data: state.data }; }; const mapDispatchToProps = (dispatch) => { return { loadData: async (skip: number, take: number) => {
伪代码中使用的类型:
type Props = { data: DataSource, loadData: (skip: number, take: number) => void }; type DataSource = {
他们完成了第一个任务-将数据分批加载和存储在Redux中。 现在让我们继续进行操作。 最常见的任务是添加-删除-修改行。 我们希望Web应用程序的每个组件都能做到这一点。 该方案很简单:

某些组件是要管理网格数据的Web应用程序的组件。
让我们来看一下该方案:
- 所有数据操作均通过Redux reducer执行。 要添加-删除-更改行,足以匹配相应的动作(ADD_ROW,DELETE_ROW,UPDATE_ROW)。 Reducers将调整Redux存储库中的数据。
- 一旦Redux中的数据发生更改,网格容器就会从Redux中提取当前数据。
- 并给他们呈现。 演示文稿更新呈现的页面。
滚动浏览Redux
以编程方式管理滚动是必需的功能。 最常见的情况是滚动到突出显示的条目。 例如,用户在列表中创建一个新条目。 带有排序的记录在列表的中间。 您需要以编程方式选择它并滚动到它。 通过Redux做到这一点将是一件好事。

通过Redux管理选择并不难,但是如何控制滚动呢?
为此,在Redux Store中,我们将放置两个字段:
scrollToIndex字段是可以理解的。 如果要滚动,请在scrollToIndex中设置所需行的编号。 此数字将被转移到网格,网格将立即滚动到它:

scrollSignal字段的作用是什么? 它解决了重新滚动到相同索引的问题。 如果我们已经执行过滚动到索引100的软件,则滚动到相同索引将不再起作用。 因此,使用了scrollSignal字段,当更改时,网格将重新滚动到scrollToIndex。 处理SCROLL操作时,Reducer中的ScrollSignal会自动递增:

滚动控制伪代码:
class GridContainer extends React.Component<Props> { props: Props; render(): React.Element<any> { return <Grid // . dataSource={this.props.data} // , .. scrollToIndex={this.props.scrollToIndex} // , . scrollSignal={this.props.scrollSignal} />; } }
const mapStateToProps = (state) => { return { data: state.data, scrollToIndex: state.scrollToIndex, scrollSignal: state.scrollSignal }; }; export default connect(mapStateToProps)(GridContainer);
伪代码中使用的类型:
type Props = { data: DataSource, scrollToIndex: ?number, scrollSignal: number };
结论(由Redux撰写)
提议的与Redux的交互方案当然不是通用的。 它们适用于我们开发的网格,因为我们针对这些方案优化了网格,并为其创建了适当的API。 这些方案不适用于任何第三方网格,因此将本文作为实现与Redux交互的一个示例。
最后结论(关于第1和第2条)
在开发网格时,我们了解到,理想情况下,网格不是我们的应用程序的一部分,而是一个独立的项目,值得在github上发布和开发。 因此,我们没有在代码中使用应用程序的主题条款,而是添加了不必要的依赖项。 但是随着功能的扩展,坚持这一点变得越来越困难,因为我们尚未将其分配给单独的项目,但是我们应该立即完成。 Github仍在计划中。
编写自己的网格是我们的正确决定。 我们有足够的时间来实现我们想要的一切(虚拟化,使用redux,批量加载,使用键盘,使用列,使用背光进行类似搜索等)。 最初,我们在第三方网格上投入了大量资金,希望它能在我们的情况下迅速发展。 使用它,我们了解了网格的总体工作原理,存在的问题,如何解决它们以及我们最终想要解决的问题。 并做出了决定。