此篇文章笔者将围绕 React 中自定义 hooks 给大家讲讲自定义 hooks 的概念以及我们要如何来设计编写自定义 hooks...
自定义 hooks 是基于 React Hooks 的一个拓展,我们可以根据业务需求制定满足业务需要的组合 hooks,更注重的是逻辑单元。怎样把一段逻辑封装起来,做到复用,这才是自定义 hooks 的初衷。
自定义 hooks 也可以说是 React Hooks 的聚合产物,其内部有一个或者多个 React Hooks 组成,用于解决一些复杂逻辑。
一个传统自定义 hooks 长下面这个样子:
function useXXX(参数A, 参数B, ...) {
/*
实现自定义 hooks 逻辑
内部应用了其他 React Hooks
*/
return [xxx, ...]
}
复制代码
使用:
const [xxx, ...] = useXXX(参数A, 参数B, ...)
复制代码
自定义 hooks 参数 可能是以下内容:
hooks
初始化值useRef
获取的 DOM
元素或者组件实例自定义 hooks 返回值 可能是以下内容:
useState
或者 useReducer
首先我们要明白,开发者编写的自定义 hooks 本质上就是一个函数,而且在函数组件中被执行。自定义 hooks 驱动本质上就是函数组件的执行。
自定义 hooks 的驱动条件主要有两点:
props
改变带来的函数组件执行。useState
或 useReducer
改变 state
引起函数组件的更新。自定义 hooks 内部至少要有一个 React Hooks,那么自定义 hooks 也同样要遵循 React Hooks 的规则,不能放在条件语句中,而且要保持执行顺序的一致性。 这是为什么呢?
这是因为在更新过程中,如果通过 if 条件语句,增加或者删除 hooks,那么在复用 hooks 的过程中,会产生复用 hooks 状态和当前 hooks 不一致的问题。所以在开发时一定要注意 hooks 顺序的一致性。
接下来我们来实现一个能够 自动上报 页面浏览量|点击时间 的自定义 hooks -- useLog
。
通过这个自定义 hooks,来 控制监听 DOM 元素,分清楚依赖关系。
编写自定义 hooks:
export const LogContext = createContext({});
export const useLog = () => {
/* 定义一些公共参数 */
const message = useContext(LogContext);
const listenDOM = useRef(null);
/* 分清依赖关系 */
const reportMessage = useCallback(
function (data, type) {
if (type === "pv") {
// 页面浏览量上报
console.log("组件 pv 上报", message);
} else if (type === "click") {
// 点击上报
console.log("组件 click 上报", message, data);
}
},
[message]
);
useEffect(() => {
const handleClick = function (e) {
reportMessage(e.target, "click");
};
if (listenDOM.current) {
listenDOM.current.addEventListener("click", handleClick);
}
return function () {
listenDOM.current &&
listenDOM.current.removeEventListener("click", handleClick);
};
}, [reportMessage]);
return [listenDOM, reportMessage];
};
复制代码
在上面的代码中,使用到了如下4个 React Hooks:
useContext
获取埋点的公共信息,当公共信息改变时,会统一更新。useRef
获取 DOM 元素。useCallback
缓存上报信息 reportMessage
方法,里面获取 useContext
内容。把 context
作为依赖项,当依赖项发生改变时,重新声明 reportMessage
函数。useEffect
监听 DOM 事件,把 reportMessage
作为依赖项,在 useEffect
中进行事件绑定,返回的销毁函数用于解除绑定。依赖关系:context
发生改变 -> 让引入 context
的 reportMessage
重新声明 -> 让绑定 DOM 事件监听的 useEffect
里面能够绑定最新的 reportMessage
使用自定义 hooks:
import React, { useState } from "react";
import { LogContext, useLog } from "./hooks/useLog";
const Home = () => {
const [dom, reportMessage] = useLog();
return (
<div>
{/* 监听内部点击 */}
<div ref={dom}>
<button> 按钮 1 (内部点击) </button>
<button> 按钮 2 (内部点击) </button>
<button> 按钮 3 (内部点击) </button>
</div>
{/* 外部点击 */}
<button
onClick={() => {
console.log(reportMessage);
}}
>
外部点击
</button>
</div>
);
};
// 阻断 useState 的更新效应
const Index = React.memo(Home);
const App = () => {
const [value, setValue] = useState({});
return (
<LogContext.Provider value={value}>
<Index />
<button onClick={() => setValue({ cat: "小猫", color: "棕色" })}>
点击
</button>
</LogContext.Provider>
);
};
export default App;
复制代码
如上,当 context
发生改变时,能够达到正常上报的效果。小细节:使用 React.memo
来阻断 App
组件改变 state
给 Home
组件带来的更新效应。
刚开始时依次点击按钮1,2,3,效果如下:
点击点击按钮后,再依次点击按钮1,2,3时,效果如下:
本文参考:React 进阶实践指南[2],感兴趣的小伙伴可以去瞧瞧~
以上就是笔者对于自定义 hooks 的一些理解,若有不足欢迎大家指出,如果觉得还不错的话,也可以留下你的点赞哟~
关于本文
https://juejin.cn/post/7175914445057556539
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有