题图 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 <div
onMouseMove={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"
}}>
<div
style={{
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