[前端]使用material-table的踩坑经历 (一种高效使用第三方React UI控件的通用思路)

直接给你答案: useRef

高效使用意味着:对于一个卡了你几个小时的bug或者功能实现,本文的方法可能会帮助你直接秒杀,然后愉快地早点下班做爱做的事。

Intro

写React的前端程序员,应该没有谁不使用第三方库的。这些控件可能是UI控件、状态管理和测试库等等,你可以在这里了解更多类型的第三方库:awesome-react

我在公司的前端项目频繁使用了 material-table ,因为项目是一个控制面板Dashboard,所以使用table基本是不可避免的。这个第三方UI库是materia-ui官方文档推荐的。

这个UI库功能很强大(支持pagination,grouping,sorting,style customisation),基本上可以无脑直接采用。对于项目初期快速做功能原型,其实是没有什么问题的。

然鹅

如果你看 material-table 的demo,分页、PageSize和排序等会有这样的问题:

  • 你用鼠标点去了第3页,一刷新页面,你又回到了第1页。PageSize和排序也是有这个问题,一刷新就回到默认的位置。

上面的问题用户体验是很差的,比如:

  • 一刷新所有状态重置。
  • 不能记住用户的选择状态(比如,排序和PageSize)。
  • 用户不能分享链接,直接跳到某一页。
  • History Go Back 或者 Go Forward 回不到历史状态。

如何记住用户选择的页面状态?

把用户的选择放在URL上面。(当然要看什么页面,一些表单提交页面不适用了)

比如下面的样子:

example.com/#/alerts?deviceModel=Well1&orderBy=created_at&pageSize=10&status=active,silenced

表格的状态更改都会在URL里面呈现。比如用户点了下一页,换了排序条件或者改变了内容筛选的条件等等。

那问题来了,可以把material-table改为想要的样子吗?

什么样子呢?就是:

  • 刷新页面后,控件能获取url的QueryString的页码排序等数据,然后再fetch api的数据,渲染material-table
  • History back and forward 也可以实现上一步效果。

这个问题还有第二个问法:我可以直接在父控件只使用props把子控件改为想要的样子吗?

答案是:No or Yes.

No. 如果你只是看material-table props option文档。你会发现,按照react的标数据流做法(改变props),是不能传data同时改页码,pageSize和sorting的。

等等,props option里面不是有initialPage和pageSize吗,控件每次渲染的时候再改变这两个值不就可以了?initialPage可以,但是,pageSize和sorting并没有给你修改的参数。

Yes.

YES NO.1 把table的各个部分替换为自己的控件

material-table 支持把各个部分替换为自己的控件。比如pagination选择器,pageSize和sorting header等。你可以直接用material-ui的table部件替换。如果你把各个部件替换了,其实你就是等同于做了一个自己的table控件。那就没必要使用material-table了。

如果你把table的各个部分都替换了,你还要自己管理状态。这点会很麻烦,毕竟代码是写多错多。我同事一开始就是使用了material-ui的table-pagination替换了material-table的pagination选择器。代码量直接翻倍,毕竟我们都是想用第三方控件偷懒。

YES No.2 使用useRef

你还记得getElementById吗?

在没有react之前,前端程序员基本都是要直接操作DOM的。熟悉使用各种DOM选择器是上古时代前端程序员的基本技能。

有了react之后,有了Virtual DOM,还有这种方便的控件。一层套一层,你可能已经忘记了上古年代直接getElementById然后innerHTML的历史。

慢着!对于material-table,我们能直接拿到这个DOM吗?

可以的。当然不是真是DOM,我们拿的是material-table整个实例对象。

对于React,useRef可以直接拿到DOM,也能拿到component实例。你可以在这里了解更多:

拿到ref之后有啥用?

直接想怎么改就怎么改。material-table内部是通过DataManager管理整个表格的状态和行为的,你可以去这里的源码了解具体的接口。各种内部的方法因有尽有,都是文档都没有提及的。

你可以去下面的issue看看具体的案例分析。这个答案就是我提供的。

https://github.com/mbrn/material-table/issues/1480#issuecomment-604289636

具体的流程是:

一图胜千言

总结

  • react是单向数据流的,除了使用props改变子控件状态,还可以试一下useRef。
  • 获取控件的ref后,可以看源码获取更深入的修改方法。

完。

本文写作耗时约2小时。

Leave a Reply

Your email address will not be published. Required fields are marked *