高阶组件
高阶组件是参数为组件,返回值是新组件的函数。
如果存在某些组件的实现流程是相同的,可以将它们的共有流程抽离成一个抽象组件,编写其高阶组件:
// HOC.jsx
import React, { PureComponent } from "react";
export class CC extends PureComponent {
render() {
return <div>CC</div>;
}
}
export const FC = () => {
return <div>FC</div>;
};
function EnhancedClassComponent(WrappedComponent) {
return class NewClassComponent extends PureComponent {
render() {
return <WrappedComponent {...this.props} />;
}
};
}
function EnhancedFunctionComponent(WrappedComponent) {
return function NewFunctionComponent(props) {
return <WrappedComponent {...props} />;
};
}
const CWithEnhance = EnhancedClassComponent(CC);
const FWithEnhance = EnhancedFunctionComponent(FC);
export default function HOC() {
return (
<>
<CWithEnhance name="CC" />
<FWithEnhance name="FC" />
</>
);
}
例子实现了一个包装函数:
应用场景
应用1:增强props
类似于偏函数的思想,可以先对组件初始化一些数据,再返回新的 “增强型” 的组件:
- import React, { PureComponent } from "react";
+ import React, { PureComponent, createContext } from "react";
+ const UserContext = createContext({
+ language: "chinese",
+ region: "China",
+ });
export const FC = ({ name, language, region }) => {
+ return <div>{`name:${name} language:${language} region:${region}`}</div>;
};
export class CC extends PureComponent {
render() {
return (
+ <div>{`name:${this.props.name} language:${this.props.language} region:${this.props.region}`}</div>
);
}
}
function EnhancedClassComponent(WrappedComponent) {
return class NewClassComponent extends PureComponent {
render() {
return (
+ <UserContext.Consumer>
+ {(user) => {
- return <WrappedComponent {...this.props} />;
+ return <WrappedComponent {...this.props} {...user} />;
+ }}
+ </UserContext.Consumer>
);
}
};
}
function EnhancedFunctionComponent(WrappedComponent) {
return function NewFunctionComponent(props) {
return (
+ <UserContext.Consumer>
+ {(user) => {
- return <WrappedComponent {...props} />;
+ return <WrappedComponent {...props} {...user} />;
+ }}
+ </UserContext.Consumer>
);
};
}
const CWithEnhance = EnhancedClassComponent(CC);
const AWithEnhance = EnhancedFunctionComponent(FC);
export default function HOC() {
return (
+ <UserContext.Provider value={{ language: "zh-CN", region: "CN" }}>
<CWithEnhance name="CC" />
<AWithEnhance name="FC" />
+ </UserContext.Provider>
);
}
应用2:渲染判断鉴权
场景1:登录鉴权
如果出现需要判断登录的场景,这时用高阶组件可以在渲染前做出逻辑判断,返回渲染结果:
import React from "react";
const LoginPage = () => {
return <h2>Login</h2>;
};
const CartPage = () => {
return <h2>Cart</h2>;
};
const withAuth = (WrappedComponent) => {
const NewCpn = (props) => {
if (props.isLogin) return <WrappedComponent {...props} />;
return <LoginPage {...props} />;
};
NewCpn.displayName = "AuthCpn";
return NewCpn;
};
const AuthCartPage = withAuth(CartPage);
export default function Auth() {
return (
<>
<AuthCartPage isLogin={false} />
</>
);
}
场景2:劫持生命周期
如果需要测试组件渲染时长,一般做法是在类的生命周期函数 componentWillMount
和 componentDidMount
中使用 Date.now()
函数获取时间戳再求差值;高级做法是使用高阶组件生成一个包装函数,将组件放入其中再按照传统方法求值:
import React, { Component } from "react";
const LoginPage = () => {
return <h2>Login</h2>;
};
const withRenderTime = (WrappedComponent) => {
return class extends Component {
UNSAFE_componentWillMount() {
this.startTime = Date.now();
}
componentDidMount() {
this.endTime = Date.now();
const delta = this.endTime - this.startTime;
console.log(delta);
}
render() {
return <WrappedComponent {...this.props} />;
}
};
};
const LoginTime = withRenderTime(LoginPage);
export default function Time() {
return (
<>
<LoginTime />
</>
);
}