概述
高阶组件并非一个组件,而是增强组件功能的一个函数。
高阶组件的作用是对多个组件公共逻辑进行横向抽离。
示例
ChildCom1.jsx
import React from 'react';
function ChildCom1(props) {
return (
<div>
这是子组件1
<div>姓名:{props.name}</div>
</div>
);
}
export default ChildCom1;
ChildCom2.jsx
import React from 'react';
function ChildCom1(props) {
return (
<div>
这是子组件2
<div>姓名:{props.age}</div>
</div>
);
}
export default ChildCom2;
withLog.js
import {useEffect} from "react";
/**
* 日志打印(抽离为高阶组件)
* @param Com 接收一个组件
* @returns {(function())|*} 返回一个新组件
*/
export default function withLog(Com) {
return function NewCom(props) {
useEffect(() => {
// 日志打印
console.log(`${Com.name}已经创建,创建时间是:`, new Date().toLocaleString());
return function () {
// 组件销毁时执行
console.log(`${Com.name}已经销毁,销毁时间是:`, new Date().toLocaleString());
}
}, []);
// 一般来讲,传入的组件会作为新组件的视图返回
return <Com {...props}/>
}
}
withTimer.js
import {useEffect, useState} from "react";
export default function withTimer(Com) {
return function NewCom(props) {
const [counter, setCounter] = useState(1)
useEffect(() => {
// 定时器
const timer = setInterval(() => {
console.log(counter)
setCounter(counter + 1)
}, 1000)
return () => {
clearInterval(timer)
}
}, [counter]);
return <Com {...props} />
}
}
App.js
import ChildCom1 from "./components/ChildCom1";
import ChildCom2 from "./components/ChildCom2";
import withLog from "./HOC/withLog";
import withTimer from "./HOC/withTimer";
const NewChildCom1 = withTimer(withLog(ChildCom1))
const NewChildCom2 = withTimer(withLog(ChildCom2))
function App() {
return (
<div className="App">
<h1>我是 App</h1>
<NewChildCom1 name={"xiuxiu"}/>
<NewChildCom2 age={18}/>
</div>
);
}
export default App;
应用场景
Next 中,可以在 app/layout.tsx 中预留一个可以编写全局初始化逻辑的代码:
/**
* 全局初始化函数,有全局单次调用的代码,都可以写到这里
*/
const doInit = useCallback(() => {
console.log("hello 欢迎来到我的项目");
}, []);
// 只执行一次
useEffect(() => {
doInit();
}, []);
开发环境中可能会看到 useEffect 执行了 2 次,这是正常现象,生产环境不会出现这个问题。
可以封装出一层 InitLayout,而不要把初始化逻辑直接写到 RootLayout 中,可以更好地维护初始化逻辑,防止后续扩展代码时出现执行时机的冲突。(比如引入全局状态管理后,要先执行 RootLayout 的 Provider 组件,才能获取到 useDispatch)
/**
* 执行初始化逻辑的布局(多封装一层)
* @param children
* @constructor
*/
const InitLayout: React.FC<
Readonly<{
children: React.ReactNode;
}>
> = ({ children }) => {
/**
* 全局初始化函数,有全局单次调用的代码,都可以写到这里
*/
const doInit = useCallback(() => {
console.log("hello 欢迎来到我的项目");
}, []);
// 只执行一次
useEffect(() => {
doInit();
}, []);
return <>{children}</>
};
758

被折叠的 条评论
为什么被折叠?



