HoC是什么?
高阶组件(HoC)是 React 中用于 复用组件逻辑 的一种高级技巧。HoC 自身不是 React API 的一部分,它是一种基于 React 的组合特性而形成的设计模式。
具体而言,高阶组件是参数为组件,返回值为新组件的函数。重点是复用逻辑
不使用HoC
Child1组件:
// Child1组件:监听窗口resize,展示窗口大小
const Child1 = () => {
const [position, setPosition] = useState({
x: document.documentElement.clientWidth,
y: document.documentElement.clientHeight,
})
const updatePosition = () => {
setPosition({
x: document.documentElement.clientWidth,
y: document.documentElement.clientHeight,
})
}
useEffect(() => {
window.addEventListener('resize', updatePosition)
return () => {
window.removeEventListener('resize', updatePosition)
}
}, [position])
return (
<div>
x:{position.x}
y:{position.y}
</div>
)
}
Child2组件:
// child2组件,也是展示窗口的大小
const Child2 = () => {
const [position, setPosition] = useState({
x: document.documentElement.clientWidth,
y: document.documentElement.clientHeight,
})
const updatePosition = () => {
setPosition({
x: document.documentElement.clientWidth,
y: document.documentElement.clientHeight,
})
}
useEffect(() => {
window.addEventListener('resize', updatePosition)
return () => {
window.removeEventListener('resize', updatePosition)
}
}, [position])
return (
<div>
x:{position.x}
y:{position.y}
</div>
)
}
展示:
import React, { useState, useEffect } from 'react'
import ReactDOM from 'react-dom'
const App = () => {
return (
<div>
<Child1 />
<Child2 />
</div>
)
}
ReactDOM.render(<App />, document.getElementById('root'))
使用HoC提取相同逻辑
1:提取相同逻辑给包装组件,入参是组件(可以接收多个参数),出参也是组件
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
// 1: 约定采用with开头命名,函数组件内部返回一个类组件
const withResize = (MyComponent) => {
// 2: 形参首字母大写
return class Resize extends Component {
//----------------- 共同的逻辑
state = {
x: document.documentElement.clientWidth,
y: document.documentElement.clientHeight,
}
updatePosition = () => {
this.setState({
x: document.documentElement.clientWidth,
y: document.documentElement.clientHeight,
})
}
componentDidMount() {
window.addEventListener('resize', this.updatePosition)
}
componentWillUnmount() {
window.removeEventListener('resize', this.updatePosition)
}
//----------------- 共同的逻辑
render() {
//HOC 不会修改传入的组件,也不会使用继承来复制其行为 将数据通过props方式传递
return <MyComponent {...this.state} />
}
}
}
2:修改子组件逻辑,通过props接收包装组件传递的数据
const Child1 = (props) => {
//通过props接收包装组件传递的数据
return (
<div>
x:{props.x}
y:{props.y}
</div>
)
}
const Child2 = (props) => {
//通过props接收包装组件传递的数据
return (
<div>
x:{props.x}
y:{props.y}
</div>
)
}
3:接收被包装后的组件并渲染
// 3:接收被包装后的组件并渲染
const Child1WithResize = withResize(Child1)
const Child2WithResize = withResize(Child2)
const App = () => {
// 4:渲染
return (
<div>
<Child1WithResize />
<Child2WithResize />
</div>
)
}
ReactDOM.render(<App />, document.getElementById('root'))
使用HoC 实现条件渲染
当data为空数组的时候 渲染<Empty/>组件,否则正常渲染列表
import React, { useState } from 'react';
import { Empty, Menu } from 'antd';
import { isArray, isEmpty } from 'lodash';
const defalutData = [
{ label: 'JavaScript', value: 1 },
{ label: 'Vue', value: 2 },
{ label: 'React', value: 3 },
];
export default function ({ value = defalutData, ...others }) {
const [data, setData] = useState(value);
const List = ({ data }) =>
isArray(data) && (
<Menu style={{ width: 200 }}>
{data?.map((item, index) => (
<Menu.Item key={index} value={item?.value}>
<span style={{ color: 'white' }}>{item?.label}</span>
</Menu.Item>
))}
</Menu>
);
const WithData = (Component) => {
return function WrapperedComponent({ data, ...others }) {
// 条件渲染
if (isEmpty(data)) return <Empty />;
return <Component data={data} {...others} />;
};
};
const WithDataComponent = WithData(List);
return <WithDataComponent data={data} {...others} />;
}