1 概念
const EnhancedComponent = higherOrderComponent(WrappedComponent)
- 组件是将 props 转换为 UI,而高阶组件是将组件转换为另一个组件。
- 使用高阶组件可实现:
- 复用逻辑
- 增强props,例如react-router的withRouter组件
- 控制渲染
- 常用的高阶组件有两种方式
2 正向代理
- 传给源组件的props属性都需要经过包裹函数HOC,也就是HOC函数代理了源组件的属性,在这一层中我们可以对props做一些额外操作
function HOC(WrapComponent) {
return function HocComponent(props) {
return <WrapComponent {...props} />;
};
}
function Inner(props) {
const { name } = props;
return (
<>
<div>inner component</div>
<div>name:{name}</div>
</>
);
}
const HocInner = HOC(Inner);
ReactDOM.render(<HocInner name="weison" />, document.getElementById("root"));
2.1 增强props
function HOC(WrapComponent) {
return function HocComponent(props) {
const enhancedProps = {
...props,
city: "广州",
};
return <WrapComponent {...enhancedProps} />;
};
}
function Inner(props) {
const { name, city } = props;
return (
<>
<div>inner component</div>
<div>name:{name}</div>
<div>city:{city}</div>
</>
);
}
const HocInner = HOC(Inner);
ReactDOM.render(<HocInner name="weison" />, document.getElementById("root"));

2.2 复用逻辑
function HOC(WrapComponent) {
return function HocComponent(props) {
const enhancedProps = {
...props,
city: "广州",
};
return (
<>
<h1>简介</h1> // +
<WrapComponent {...enhancedProps} />
</>
);
};
}
function Inner(props) {
const { name, city } = props;
return (
<>
<div>inner component</div>
<div>name:{name}</div>
<div>city:{city}</div>
</>
);
}
const HocInner = HOC(Inner);
ReactDOM.render(<HocInner name="weison" />, document.getElementById("root"));
2.3 抽离state控制更新
- 这里把count的状态放到HocComponent函数内管理
function HOC(WrapComponent) {
return function HocComponent(props) {
const [count, setCount] = useState(0);
const handleCountClick = () => setCount(count + 1)
const enhancedProps = {
...props,
city: "广州",
};
return (
<>
<h1>简介</h1>
<WrapComponent {...enhancedProps} count={count} handleCountClick={handleCountClick} />
</>
);
};
}
function Inner(props) {
const { name, city, count, handleCountClick } = props;
return (
<>
<div>inner component</div>
<div>name:{name}</div>
<div>city:{city}</div>
<div onClick={handleCountClick}>count:{count}</div>
</>
);
}
const HocInner = HOC(Inner);
ReactDOM.render(<HocInner name="weison" />, document.getElementById("root"));
2.4 条件渲染
- 在外层控制被包裹组件是否渲染,这种情况应用于,权限隔离,懒加载 ,延时加载等场景
- 路由权限控制示例
import { message } from "antd";
import React, { useEffect } from "react";
import { Redirect } from "react-router-dom";
export default function HOC(Route) {
return function HocComponent(props) {
const isLogin = localStorage.getItem("token");
useEffect(() => {
if (!isLogin) {
message.warning("请先登录");
}
}, []);
return isLogin ? <Route {...props} /> : <Redirect to="/login" />;
};
}
import React from "react";
import ReactDOM from "react-dom";
import { Router, Switch, Route } from "react-router-dom";
import history from "./history";
import Login from "./pages/login";
import Home from "./pages/home";
import HOC from "./router/PrivateRoute.js";
const PrivateRoute = HOC(Route);
export default function Index() {
return (
<Router history={history}>
<Switch>
<Route path="/login" component={Login} />
<PrivateRoute path="/" component={Home} />
</Switch>
</Router>
);
}
ReactDOM.render(<Index />, document.getElementById("root"));
import { message } from "antd";
import React, { useEffect } from "react";
import { Redirect, Route } from "react-router-dom";
function PrivateRoute() {
return function HocComponent(props) {
const isLogin = localStorage.getItem("token");
useEffect(() => {
if (!isLogin) {
message.warning("请先登录");
}
}, []);
return isLogin ? <Route {...props} /> : <Redirect to="/login" />;
};
}
export default PrivateRoute();
3 反向继承
function HOC(WrapComponent) {
return class extends WrapComponent {};
}
class Inner extends React.Component {
render() {
return <>Inner</>;
}
}
const HocInner = HOC(Inner);
ReactDOM.render(<HocInner />, document.getElementById("root"));
- 反向继承我现阶段觉得不常用,更多介绍和用法可看文末的参考资料写得很详细
4 注意事项
function HOC(WrapComponent) {
return class extends React.Component {
state = {
test: "test",
};
render() {
return <WrapComponent {...this.props} />;
}
};
}
function Inner(props) {
const { name } = props;
return (
<>
<div>inner component</div>
<div>name:{name}</div>
</>
);
}
const HocInner = HOC(Inner);
function App() {
const myRef = useRef();
useEffect(() => {
console.log("myRef", myRef.current);
}, []);
return <HocInner name="weison" ref={myRef} />;
}
ReactDOM.render(<App />, document.getElementById("root"));

function HOC(WrapComponent) {
class HocComponent extends React.Component {
render() {
return <WrapComponent {...this.props} />;
}
}
return React.forwardRef((props, ref) => <HocComponent {...props} forwardRef={ref} />);
}
function Inner(props) {
const { name,forwardRef } = props;
return (
<>
<div ref={forwardRef}>inner component</div>
<div>name:{name}</div>
</>
);
}
const HocInner = HOC(Inner);
function App() {
const myRef = useRef();
useEffect(() => {
console.log('myRef',myRef.current);
}, []);
return <HocInner name="weison" ref={myRef} />;
}
ReactDOM.render(<App />, document.getElementById("root"));

参考资料
「react进阶」一文吃透React高阶组件(HOC)