内容简介:先感谢掘金这个平台让我可以看到别人的思想,别人的智慧。说真的,在这个平台上还是看到了许多有营养的文章。目前的我是产不出像大佬那样富有营养的文章,那就记录一点我在工作中的事情,如有说错的地方或是有不合理的地方,希望各位大佬指出。项目的背景是做一个总管理后台,我的那个项目直接用的就是蚂蚁金服的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 或者 赞。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Book of CSS3
Peter Gasston / No Starch Press / 2011-5-13 / USD 34.95
CSS3 is the technology behind most of the eye-catching visuals on the Web today, but the official documentation can be dry and hard to follow. Luckily, The Book of CSS3 distills the heady technical la......一起来看看 《The Book of CSS3》 这本书的介绍吧!