我们要理解什么是高阶组件可以先从高阶函数开始。高阶函数指的是一个函数接受一个或者多个函数作为参数或者返回一个函数就可以称之为高阶函数。我们平时用到的reduce,map,filter就是高阶函数。高阶组件和高阶函数类似,高阶组件(higher-order-component,简称HOC)它是参数为组件返回值为新组件的函数。它是一个函数,但是参数和返回值都是组件,一般是用于组件之间代码的复用。它自身并不是react api的一部分,是一种基于react的组合特性而形成的设计模式。
下面是一个简单的高阶组件,当高阶组件中返回的是无状态组件,那这个高阶组件可以看成是一个高阶函数。
function HigherOrderComponent(WrappedComponent) {
return <WrappedComponent />;
}
属性代理(Props Proxy)是最常见的高阶组件的使用方式,它通过做一些操作将被包裹组件的props 和新生的props一起传递给此组件。可以看出,属性代理它其实就是一个函数接受被包裹组件作为参数并返回一个类,这个类的render方法中返回被包裹的组件。
//无状态
function HigherOrderComponent(WrappedComponent) {
return props => <WrappedComponent {...props} />
}
//有状态
function HigherOrderComponent(WrappedComponent) {
return class extends React.Component {
render() {
return <WrappedComponent {...this.props} />
}
}
}
1、增加props。可以在不修改原有代码的情况下,增加新的props。
import React, { PureComponent } from 'react';
import ReactDOM from 'react-dom'
//定义了一个名为WithEnhanceProps的高阶组件
function WithEnhanceProps(WrappedComponent) {
class NewComponent extends React.Component {
render() {
return <WrappedComponent {...this.props} author='王小波' />
}
}
//进行重新命名用到displayName属性,方便后续的开发调试
NewComponent.displayName = 'WithEnhanceProps'
return NewComponent;
}
class Home extends PureComponent { render() { return <h4>Home:{`我最喜欢的书籍是:${this.props.text},作者:${this.props.author}`}</h4> } }
//调用 WithEnhanceProps,进行包裹
const WithHome = WithEnhanceProps(Home);
class App extends PureComponent {
render() {
return (
<div>
App
{/* <Home text='青铜时代' /> */}
<WithHome text='青铜时代' ></WithHome>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'));
· 2、增强props。如下代码所示,在子父组件数据传递时,利用高阶组件来共享Context。
import React, { PureComponent, createContext } from 'react';
import ReactDOM from 'react-dom'
const UserContext = createContext({
text: '爱你就像爱生命',
user: '王小波'
});
function withUser(WrappedComponent) {
return props => {
return (
<UserContext.Consumer>
{user => { return <WrappedComponent {...props} {...user} /> }}
</UserContext.Consumer>
)
}
}
class Home extends PureComponent { render() { return <h4>Home: 王小波说的最动人的两句话:{this.props.text}{this.props.other}</h4> } }
class Detail extends PureComponent {
render() {
return (
<ul>
<li>{this.props.text}</li>
<li>{this.props.other}</li>
</ul>
)
}
}
const UserHome = withUser(Home);
const UserDetail = withUser(Detail);
class App extends PureComponent {
render() {
return (
<div>
App
<UserContext.Provider value={{ text: "一想到你,我这张丑脸上就泛起微笑 ", other: '你要是愿意,我就永远爱你 ,你要是不愿意,我就永远相思' }}>
<UserHome />
<UserDetail />
</UserContext.Provider>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'));
3、对生命周期进行劫持,在生命周期中完成自己的逻辑。
import React, { PureComponent } from 'react';
import ReactDOM from 'react-dom'
function withRenderTime(WrappedComponent) {
return class extends PureComponent {
UNSAFE_componentWillMount() {
this.beginTime = Date.now();
}
componentDidMount() {
this.endTime = Date.now()
const interval = this.endTime - this.beginTime;
console.log(`${WrappedComponent.name}渲染时间: ${interval}ms`)
}
render() {
return <WrappedComponent {...this.props} />
}
}
}
class Home extends PureComponent { render() { return <h3>Home</h3> } }
const TimeHome = withRenderTime(Home);
class App extends PureComponent { render() { return (<><TimeHome /></>) } }
ReactDOM.render(<App />, document.getElementById('root'));
在前面的学习中我们了解到因为函数式组件没有实例,不能获取到对应的组件对象,所以ref不能应用于函数式组件,但是在平时的开发中有这样的需求,这时我们要用到forwardRef高阶组件,代码示例如下:
import React, { PureComponent, createRef, forwardRef } from 'react';
import ReactDOM from 'react-dom'
class Home extends PureComponent {
render() { return <h3>Home</h3> }
}
// 高阶组件forwardRef
const About = forwardRef(function (props, ref) {
return <p ref={ref}>About</p>
})
class App extends PureComponent {
constructor(props) {
super(props)
this.homeRef = createRef();
this.aboutRef = createRef();
}
render() {
return (<>
<h3> hello App</h3>
<Home ref={this.homeRef} />
<About ref={this.aboutRef} />
<button onClick={this.printRef}>click</button>
</>)
}
printRef = () => {
console.log(this.homeRef.current);
console.log(this.aboutRef.current)
}
}
ReactDOM.render(<App />, document.getElementById('root'));