内容简介:先感谢掘金这个平台让我可以看到别人的思想,别人的智慧。说真的,在这个平台上还是看到了许多有营养的文章。目前的我是产不出像大佬那样富有营养的文章,那就记录一点我在工作中的事情,如有说错的地方或是有不合理的地方,希望各位大佬指出。项目的背景是做一个总管理后台,我的那个项目直接用的就是蚂蚁金服的ant-design-pro,不得不夸赞这个真的是太好用了。然后做这种管理后台总是会遇到很多表格,列表之类的展示,一般的表格和列表都会有两个最基本的诉求,那就是分页和搜索。然后我的代码中就充斥了很多这样的逻辑。 在总之就是
先感谢掘金这个平台让我可以看到别人的思想,别人的智慧。说真的,在这个平台上还是看到了许多有营养的文章。目前的我是产不出像大佬那样富有营养的文章,那就记录一点我在工作中的事情,如有说错的地方或是有不合理的地方,希望各位大佬指出。
项目的背景是做一个总管理后台,我的那个项目直接用的就是蚂蚁金服的ant-design-pro,不得不夸赞这个真的是太好用了。然后做这种管理后台总是会遇到很多表格,列表之类的展示,一般的表格和列表都会有两个最基本的诉求,那就是分页和搜索。然后我的代码中就充斥了很多这样的逻辑。 在 componentDidMount
的时候发送请求加载数据,在页码改变的时候加载数据,在客户搜索的时候加载数据......
总之就是我写了很多功能重复的代码,不行,我是一个善于思(作)考(死)的人,我要想一个办法去解决这个问题!然后我感觉react的高阶组件可以应用于此场景。
二、思考这个高阶组件要解决什么问题
本文就不在此说高阶组件到底是什么,本文主要探讨的目标在于如何利用高阶组件去解决问题,如果有对高阶组件不甚了解的同学可以先看看react官方文档 。
接下来的探讨就基本我本次开发的项目中,先讲一下本次项目开发采用的技术栈。本次是开发一个后台管理系统,项目使用了 antd
、 dva
。 其实其他的都不重要了,最重要的是这个 dva
,使用过的同学应该都知道,它提供了一个 model
的概念。也就是说我们所获取的数据是要用这个 model
去管理的。我这个高阶组件要实现的最基本的功能有一下两点:
-
翻页获取数据
-
能够根据表单搜索数据
三、开始编写
1、搭好架子
废话就不多说了,开始编写这个高阶组件,先把这个组件写出来再说!新建一个 table.js
文件,这个文件有以下内容:
import React from 'react' export default (WarpComponent)=> { return class extends React.Component { state = { formValues: {} // 表单搜素字段 page: 1, // 分页页码 num: 10 } render(){ return ( <WarpComponent {...this.props} /> ) } } } 复制代码
现在写出来的这个高阶组件已经可以直接使用了,使用的时候只需要:
import TableHoc from 'xxx' @TabelHoc export default class XXX {...} // 相当于 TableHoc(XXX) 复制代码
可以看见其实高阶组件就是一个函数,接收了组件然后返回了组件。可以看到在渲染被包裹的那个组件的时候把 props
全部解构给了被包裹的这个组件,这并不是多此一举。想象一下如果这个 WarpComponent
原本刚好是一个路由组件,当你在定义路由的页面去引用这个组件的时候,它已经被高阶组件包裹了,就是说对原本的这个 WarpComponent
的 props
传递的值现在都传递到了我们所编写的高阶组件上去了,所以,在这里,我们将原本属于 WarpComponent
的 props
“还” 给它。
2、把配置项提出来
在上面的编写中我把分页的页码和条数都设定死了,其实这是很不友好的。我们应该让它变成一个可以配置的项。修改以上的代码为:
import React from 'react' export default ({type, page, num}) => WrapComponent => { return class extends React.Component { state = { formValues: {}, page: page || 1, num: num || 10 } render(){ return ( <WarpComponent {...this.props} /> ) } } } 复制代码
在使用的时候只需要:
import TableHoc from 'xxx' @TableHoc({ page: 2, // 这里传了多少那高阶组件里初始化的值就是多少 num: 20, type: 'xxx' }) export default class XXX {...} 复制代码
这里说一下这个 type
是什么,其实这个 type
需不需要取决于你自己的项目。比如我这个项目,我用了 dva
那数据我都是用集中管理在 models
的。用过 dva
的朋友都知道,它有一个 命名空间
的概念,就是在 dispatch
的时候有一个 type
需要我们去传嘛。如果你没有使用 dva
或者 redux
。 那就直接在这个高阶组件里去管理、获取数据然后作为 props
传给被包裹的组件就行了,那相应的你也不需要这个 type
参数了。
还有一个问题,就是这个高阶组件它需要去执行 dispatch
操作嘛,那就先需要 connect
,注意,这里你是使用的 dva
还是 redux
其实根本没区别, 本质上这个 connect
也是一个高阶组件。现在我把 connect
写上去:
import TableHoc from 'xxx' import { connect } from 'dva' @connect() @TableHoc({ page: 2, // 这里传了多少那高阶组件里初始化的值就是多少 num: 20, type: 'xxx' }) export default class XXX {...} 复制代码
需要注意的是这个 connect
一定要写到 TableHoc
前面。
3、给予组件翻页,和搜索的功能
现在要说的就是这个组件核心的功能,翻页和搜索,现在 TableHoc
组件里写上两个方法:
searchData = formValues => { this.setState({ page: 1, formValues }, this.getData) } handlePageChange = (page, num) => { this.setState({ page, num }, this.getData) } 复制代码
先不去管 this.getData
这个方法,这个两个方法明显就是要给被包裹的组件使用的,所以要传给被包裹的组件。还有页码,被包裹的组件在翻页的时候肯定也是需要展示页码的,所以都传下去。
改写 render
方法:
render(){ return ( <WrapComponent ref={com => this.warpCom = com} {...this.props} {...this.state} searchData = {this.searchData} handlePageChange = {this.handlePageChange} resetData = {this.resetData} /> ) } 复制代码
可以注意我给被包裹的组件加上了一个 ref
属性,这样我就可以拿到组件的实例了。为什么要加呢,主要是我考虑到一种情况,就是除了翻页、还有表单搜索这样的一些搜索字段,可能还有一个额外的参数需要用作搜索,所以我把这个决定的权利给到被包裹的组件。接下来完善 this.getData
方法:
getData = ()=> { let elseSearchPrams = {} if ( this.warpCom && this.warpCom.getSearchParams ) { elseSearchPrams = this.warpCom.getSearchParams() } const { page, num, formValues } = this.state this.props.dispatch({ type, payload: { page, num, ...formValues, ...elseSearchPrams } }) } 复制代码
可以看到我试着去获取了一下 warpCom
有没有额外需要传入搜索的参数,在 warpCom
中只需要去定义一个名为 getSearchParams
的方法,然后返回一个包含搜索信息的对象就可以了。这里的 this.props.dispath
是 dva
提供给我的方法,我只需要根据 dva
定义的去使用去就可以了。 如果想直接使用 redux
的话按照 redux
那一套就可以了,使用 redux
的话这里就是 发起一个 action
, 那么很简单,传进来的那个 type
只要改成 redux
的 action
就可以了。
然后还有一个 resetData
方法,很明显的如果要 reset
的话,需要重置页码还有搜索参数:
resetData = ()=> { this.setState({ page: 1, formValues: {} }, this.getData) } 复制代码
然后是获取数据,一般都是在 componentDidMount
生命周期里去获取。所以在加上代码:
componentDidMount() { this.getData() } 复制代码
4、如何使用
组件的代码我们是已经编写完了。组件很简单,使用起来也很简单。只需要在页码改变的时候,或者是搜索参数改变的时候去调用这个高阶组件所提供的 handlePageChange
方法和 searchData
方法就可以了。这里我提供一个 使用范例
,范例中有完整的高阶组件的代码,也有完整的使用的代码。 在这个项目中使用了 antd
dva
,很真实的使用环境,希望可以提供帮助。在项目数据mock服务中我只处理了页码,没有去管搜索参数,有疑问可以打开 network看看搜索参数是否正常传递。
如果有疑问可以在掘金下回复我,也可以在我贴出的git项目的 issue中提出问题,我会尽力解答。
四、总结
文章写完啦,深深的感觉自己的陈述能力不足。言归正传,这就是一次高阶组件的使用,其实很多设计都是用到了高阶组件,就比如说 redux
的 connect
, 用过 antd
的朋友应该也知道在表单验证的时候有 Form.create
和 getFieldDecorator
。这些都是很经典的使用,平时我也喜欢用高阶组件去做一些权限处理啊什么的。 虽然说现在 react
已经推出了 hooks
,可能 class
类型的组件被淘汰掉只是时间的问题。试着去了解了一下 hooks
觉得我get不到其中的思想。等后续我再试着了解 hooks
看看能不能带来一个 hooks
的实现版本。
水平有限,可能说的有一些错的地方我却不自知, 希望大家指正。
最后:
使用范例地址: github.com/Chechengyi/…
我的 github地址: github.com/Chechengyi
码字不易,欢迎朋友们来一波 star 或者 赞。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。