高阶组件:高阶组件就是一个接收一个组件并返回另外一个新组件的函数。
首先, 高阶组件本身不是一个组件,而是一个函数;
其次,这个函数的参数是一个组件,返回值也是一个组件;
我们可以在高阶组件内部定义一个类组件或者函数组件作为返回结果
定义类组件返回
// 定义一个高阶组件
// 1.高阶组件会接收一个组件作为参数
function hoc(Cpn) {
class NewCpn extends PureComponent {
}
// 2.并且返回一个新的组件
return NewCpn
定义函数组件返回
// 定义一个高阶组件
// 1.高阶组件会接收一个组件作为参数
function hoc(Cpn) {
function NewCpn() {
}
// 2.并且返回一个新的组件
return NewCpn
}
高阶组件并不是React API的一部分,它是基于React的 组合特性而形成的设计模式。
高阶组件在一些React第三方库中非常常见:
比如redux中的connect;
高阶组件应用场景
应用一: props增强
例如我们可以定义一个高阶组件, 对传入的组件进行props增强, 也就是为传入的组件添加一些参数, 需要注意的是, 如果传入的组件本身也有传递参数的话, 我们在为组件注入要增强的参数的同时, 还需要将本身传递的参数也注入进来, 实例代码如下:
// 定义一个高阶组件, 对传入的组件进行props增强
function enhancedProps(WrapperCpn) {
class NewComponent extends PureComponent {
constructor() {
super()
this.state = {
userInfo: {
name: "chenyq",
age: 18
}
}
}
render() {
// 如果组件本身也有传递参数, 也需要将参数添加进来
return <WrapperCpn {...this.props} {...this.state.userInfo}/>
}
}
return NewComponent
}
// 调用高阶组件, 对组件进行props增强
const Home = enhancedProps(function(props) {
return <h2>{props.name}-{props.age}</h2>
})
const About = enhancedProps(function(props) {
return <h2>{props.name}-{props.age}-{props.names}</h2>
})
export class App extends PureComponent {
render() {
return (
<div>
{/* 展示增强后的组件 */}
<Home/>
{/* 本身也有传递参数 */}
<About names={["aaa", "bbb", "ccc"]}/>
</div>
)
}
}
高阶组件:Hoc.tsc
import React from 'react';
// 高阶组件
interface IWithPorps{
title: string;
}
const withMyHoc = (WrappedComponent: any) => {
return class _ extends React.Component<IWithPorps> {
render() {
// 可以在这里添加额外的逻辑或属性
return <WrappedComponent {...this.props} extraProp="extraValue" />;
}
}
};
export default withMyHoc;
普通组件:MyComponent.tsx
import React from 'react';
interface p{
extraProp: string;
title: string;
}
// 被高阶组件包装的组件
const MyComponent = (props: p) => {
return <div>{props.extraProp} | {props.title}</div>;
};
export default MyComponent;
使用:App.tsx
import React from 'react';
import withMyHoc from "./Hoc";
import MyComponent from "./MyComponent"
const MyCom = withMyHoc(MyComponent)
const App: React.FC = () => (
<MyCom title="高阶组件"/>
);
export default App;
应用二: 渲染判定鉴权
在开发中,我们可能遇到这样的场景:
某些页面是必须用户登录成功才能进行进入;
如果用户没有登录成功,那么直接跳转到登录页面;
这个时候,我们就可以使用高阶组件来完成鉴权操作:
// 定义一个高阶组件, 用于鉴权的操作
function loginAuth(WrapperCpn) {
return props => {
// 从本地存储中获取token, token有值表示已登录, 没有值表示未登录
const token = localStorage.getItem("token")
if(token) {
return <WrapperCpn {...props}/>
} else {
return <h2>请先登录, 再跳转到对应的页面中</h2>
}
}
}
const Cart = loginAuth(function() {
return <h2>购物车页面</h2>
})
export class App extends PureComponent {
render() {
return (
<div>
<Cart/>
</div>
)
}
}
高阶组件的意义
我们会发现利用高阶组件可以针对某些React代码进行更加优雅的处理。
当然,HOC也有自己的一些缺陷:
HOC需要在原组件上进行包裹或者嵌套,如果大量使用HOC,将会产生非常多的嵌套,这让调试变得非常困难;
HOC可以劫持props,在不遵守约定的情况下也可能造成冲突;
Hooks的出现,是开创性的,它解决了很多React之前的存在的问题
比如this指向问题、比如hoc的嵌套复杂度问题等等;