
题图 From Bing By Clm
今天跟大家聊一聊React的高阶组件,那么什么是高阶组件呢?
如果一个函数 接受一个或多个组件作为参数并且返回一个组件 就可称之为 高阶组件。
高阶组件的本质就是一个函数,这个函数的参数是组件,这个函数的返回结果是一个组件。
我们用一个案例来说明,封装一个Mouse组件,这个组件实时获取鼠标的坐标并实时显示出来。
代码如下:
import React,{Component} from 'react';class Mouse extends Component {constructor(props) {super(props);this.state = {x:0,y:0}}handleMouse=(e)=>{this.setState({x:e.clientX,y:e.clientY})}render() {return <divonMouseMove={this.handleMouse}style={{background:"red",height:"100px",width:"500px",}}><h1>x:{this.state.x}</h1><h1>y:{this.state.y}</h1></div>}}export default Mouse;
显示结果:

代码很简单,在一个div上面监听鼠标的拖动事件,实时获取坐标,并将其显示出来,在此基础之上,我们将其改造成高阶组件。
这里面需要明白几个问题,为什么要改造呢?如何改造呢?
首先来搞清楚第一个问题:假如我们的项目中有多个组件需要获取鼠标的坐标,有的组件只是显示,有的组件需要根据坐标来移动dom元素,我们改如何做呢?简单直白的方法,直接copy上面的代码,修改代码,有多少组件需要实时获取鼠标坐标就copy修改几次。
这显然不是最好方案,我们可以将获取鼠标坐标的逻辑抽离出来,构造一个高阶组件,那么如何构造呢?
再次重申一下高阶组件的定义:
如果一个函数 接受一个或多个组件作为参数并且返回一个组件 就可称之为 高阶组件。
我们根据这个定义书写代码:
// 1、定义一个函数// 2、参数为组件function HOC(Comp){//3、调用后,返回一个组件return class extends Component{constructor(props) {super(props);}render() {return <div>{/*2、参数为组件*/}<Comp/></div>}}}
以上代码便是高阶组件最简单的代码结构,下面我们来填充上面的代码,首先我们要明白,高阶组件内部返回的组件的通用逻辑是什么呢?获取鼠标的移动坐标。
代码进一步完善如下:
import React,{Component} from 'react';// 1、定义一个函数// 2、参数为组件function HOC(Comp){//3、调用后,返回一个组件return class extends Component{constructor(props) {super(props);//4、保存鼠标坐标位置this.state = {x:0,y:0}}//5、鼠标移动获取新的位置坐标handleMouse =(e)=>{this.setState({x:e.clientX,y:e.cclientY})}render() {return <div onMouseMove={this.setState}>{/*6将获取到的坐标传递给目标组件*/}<Comp x={this.state.x} y={this.state.y}/></div>}}}
阅读源码:我们在高阶组件的结构上增加了如下几个功能,定义state保存鼠标位置,监听鼠标移动事件获取新的坐标,将坐标传递给目标组件。
下面我们完成目标组件,目标组件的作用主要是显示坐标。代码如下:
class Show extends Component{constructor(props) {super(props);}render() {return <div><h2>x:{this.props.x}</h2><h2>x:{this.props.y}</h2></div>}}
最终代码如下:
import React,{Component} from 'react';// 1、定义一个函数// 2、参数为组件function HOC(Comp){//3、调用后,返回一个组件return class extends Component{constructor(props) {super(props);//4、保存鼠标坐标位置this.state = {x:0,y:0}}//5、鼠标移动获取新的位置坐标handleMouse =(e)=>{this.setState({x:e.clientX,y:e.clientY})}render() {return <div onMouseMove={this.handleMouse}>{/*2、参数为组件*/}{/*6将获取到的坐标传递给目标组件*/}<Comp x={this.state.x} y={this.state.y}/></div>}}}// 7、目标组件,主要作用是渲染显示坐标class Show extends Component{constructor(props) {super(props);}render() {return <div><h2>x:{this.props.x}</h2><h2>x:{this.props.y}</h2></div>}}// 8、将目标组件传递进入高阶组件,得到组件,此时新组件具有了获取鼠标坐标的能力let NewComponent = HOC(Show);export default NewComponent;
显示结果:

阅读最终代码,我们发现,在构造目标组件时,这个组件需要接收高阶组件获取的鼠标坐标,而获取坐标后我们将其做简单展示。
这里也可以根据这个坐标做一些其他的功能。比如根据坐标移动dom元素,那么就只需要构造一个新的组件,这个组件接收x,y坐标,然后根据坐标移动dom元素,最终代码如下:
import React,{Component} from 'react';// 1、定义一个函数// 2、参数为组件function HOC(Comp){//3、调用后,返回一个组件return class extends Component{constructor(props) {super(props);//4、保存鼠标坐标位置this.state = {x:0,y:0}}//5、鼠标移动获取新的位置坐标handleMouse =(e)=>{this.setState({x:e.clientX,y:e.clientY})}render() {return <div onMouseMove={this.handleMouse}>{/*2、参数为组件*/}{/*6将获取到的坐标传递给目标组件*/}<Comp x={this.state.x} y={this.state.y}/></div>}}}// 7、定于目标组件,接收x,y坐标参数function Move({x,y}){return <div style={{height:"100px",width:"100px",background:"yellow"}}><divstyle={{background:"red",height:"10px",width:"10px",position:"absolute",left:x,top:y}}>Move</div></div>}//8、构造新的组件let NewComponent = HOC(Move);export default NewComponent;
案例完成了,总结一下:
1、高阶组件的本质就是一个函数
2、函数的参数为一个组件,通常这个组件会接收高阶组件传入的参数
3、函数调用后返回一个新的组件
4、高阶组件内部主要是将通用的功能逻辑抽离出来
高阶组件还有一些不足,比如说高阶组件存在组件嵌套的问题,我们在下篇文章用一种新的方法来代替他。
以上便是高阶组件的使用方式,当然高阶组件还有好多其他的用法,如果你有什么其他的想法或建议,欢迎留言。
本文分享自微信公众号 - nodejs全栈开发(geekclass)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。
来源:oschina
链接:https://my.oschina.net/u/4582019/blog/4378793