高阶组件(Higher-Order Components)就是一个就是一个没有副作用的纯函数,且该函数接受一个组件作为参数,并返回一个新的组件。
实现步骤
- 首先创建一个函数
- 指定函数参数,参数应该以大写字母开头
- 在函数内部创建一个类组件或函数组件,提供复用的状态逻辑代码,并返回
- 在该组件中,渲染参数组件,同时将状态通过prop传递给参数组件(可选,如有)
- 调用该高阶组件,传入要增强的组件,通过返回值拿到增强后的组件,并将其渲染到页面
作用:
- 进行权限控制
- 路由限制
- 访问统计
- 统一布局
高阶组件的应用
props 的增强
- 假设我们要给一个组件增加一个属性, 由于当前该组件已经在很多地方使用了,那么改的话就要修改好多地方,这个时候就可以定义一个高阶组件
复制import React, { PureComponent } from 'react';
// 定义一个高阶组件
function wrap(WrappedComponent) {
// props 是传过来的属性, 在返回组件时将传过来的 props 和新增的属性一起传给组件
return props => {
return <WrappedComponent {...props} region="中国" />
}
}
// Beijing 和 Taiwan有共同的一个属性region都属于中国
class Beijing extends PureComponent {
render() {
return <h2> 北京在北方。 所属国家: {this.props.region}</h2>
}
}
class Taiwan extends PureComponent {
render() {
return <h2> 台湾在南方。 所属国家: {this.props.region}</h2>
}
}
const BeijingEx = wrap(Beijing);
const TaiwanEx = wrap(Taiwan);
class App extends PureComponent {
render() {
return (
<div>
{/* <Beijing region="中国"/> */}
{/* <Taiwan region="中国"/> */}
<BeijingEx />
<TaiwanEx />
</div>
)
}
}
export default App;
登录鉴权
- 针对所有要需要登录态的页面进行登录态鉴别,没有就跳登录页, 这里我们就可以使用高阶组件,将所有需要鉴权的页面都使用高阶组件包裹
复制import React, { PureComponent } from 'react';
class LoginPage extends PureComponent {
render() {
return <h2>LoginPage</h2>
}
}
function withAuth(WrappedComponent) {
return props => {
if (checkToken()) { // 如果已经登录过,则跳转到功能页面,否则跳转到登录页面
return <WrappedComponent {...props} />
}
return <LoginPage />
}
}
// 购物车组件
class Cart extends PureComponent {
render() {
return <h2>Cart</h2>
}
}
const AuthCart = withAuth(Cart);
export default class App extends PureComponent {
render() {
return (
<div>
<AuthCart isLogin={true}/>
</div>
)
}
}
生命周期劫持
- 可以在声明周期钩子函数中操作一个相同的操作
复制import React, { PureComponent } from 'react';
function withRenderTime(WrappedComponent) {
return class extends PureComponent {
// 即将渲染获取一个时间 beginTime
UNSAFE_componentWillMount() {
this.beginTime = Date.now();
}
// 渲染完成再获取一个时间 endTime
componentDidMount() {
this.endTime = Date.now();
const interval = this.endTime - this.beginTime;
console.log(`${WrappedComponent.name}渲染时间: ${interval}`)
}
render() {
return <WrappedComponent {...this.props} />
}
}
}
class Home extends PureComponent {
render() {
return <h2>Home</h2>
}
}
class About extends PureComponent {
render() {
return <h2>About</h2>
}
}
const TimeHome = withRenderTime(Home);
const TimeAbout = withRenderTime(About);
export default class App extends PureComponent {
render() {
return (
<div>
<TimeHome />
<TimeAbout />
</div>
)
}
}
ref 转发 (以后再学)
- 函数式组件由于没有实例,所以无法通过 ref 获取他们的实例,但可以通过 React.forwardRef 拿到
复制import React, { PureComponent, forwardRef } from 'react';
// 高阶组件forwardRef
const Profile = forwardRef(function (props, ref) {
return <p ref={ref}>Profile</p>
})
export default class App extends PureComponent {
constructor(props) {
super(props);
this.profileRef = createRef();
}
render() {
return (
<div>
<Profile ref={this.profileRef} name={"why"} />
<button onClick={e => this.printRef()}>打印ref</button>
</div>
)
}
printRef() {
console.log(this.profileRef.current);
}
}