如何写自定义 React Hook?

简介: 前端西瓜哥

大家好,我是在学习 React 的前端西瓜哥。

我们在写 React 函数组件时,如果想要复用组件的部分逻辑,可以考虑写自定义 Hook。本文会教大家如何写自定义 React Hook。

Hook 的规则

在此之前,我们先了解一下 Hook 的使用规则。

首先 Hook 只能在函数组件的顶层使用,不能在循环、条件、嵌套函数中执行。

这和 React Hook 的实现原理有关。当第一次执行函数组件时,React 会分配一个对象,然后一个个调用 Hook 时,将传入的参数或得到的结果依次放入到有序的表中缓存起来,然后保存在该对象中。

之后再次执行函数组件时,必须要保证这些 Hook 的执行顺序相同,才能做依赖项的对比,以及和前一次渲染的状态的对比等对比逻辑。

如果能 hook 可以出现循环、条件、嵌套函数中,就不能保证 Hook 执行顺序不变。

此外Hook 只能在函数组件内工作,不要在非组件函数中使用 Hook

如果你在普通函数内使用了 Hook,React 会报错。

当然如果是自定义 Hook(一个使用了 React 内置 Hook 的普通函数),然后放到函数组件内,那也是合法的。

为防止开发者不小心写岔,React 官方还写了一个名为 eslint-plugin-react-hooks 的 ESLint 插件,用于检测不合法的 Hook 调用位置,实在是太贴心了。强烈建议使用。

写自定义 Hook

自定义 Hook,就是使用了内置 Hook 的普通函数。它是对函数组件可复用的部分逻辑的做了一层封装,然后再被函数组件使用。

自定义的 Hook 必须使用 use 开头。因为 React 的官方 ESLint 插件认为 use 开头是自定义 Hook。

如果你不用 use 开头,ESLint 插件就会认为这是一个普通函数,调用时不符合 Hook 规则时不会报错,你就可能写出有问题的代码。

另外,自定义 Hook 下使用的 Hook,也必须位于顶层,这也是为了保证 hook 的顺序多次执行能保持一致。

下面我们来写几个常用的自定义 Hook。

useMount / useUnmount

我们希望实现类似类函数 componentDidMount 的效果。

const useMount = fn => {
  useEffect(() => {
    fn();
  }, []);
}

使用方式:

function App = () => {  
  // 自定义 Hook
  useEffect(() => {
    console.log('挂载');
  });
  // 原来的写法
  useEffect(() => {
    console.log('挂载');
  }, []);
}

相比原来的 useEffect 的实现,做了封装后的 useMount 更语义化一些。外也不需要写多余的依赖项,并将组件销毁的回调函数也隔离出去了。

类似类函数 componentWillUnmount 的 useUnmount Hook 实现如下:

const useUnmount = fn => {
  useEffect(() => fn, []);
}
// 用法
useUnmount(() => {
  console.log('销毁');
})

useUpdateEffect

下面我们再实现一个 useEffect 的剔除掉挂载那一次的版本,对标类函数的 componentDidUpdate。

const useUpdateEffect = (fn, deps) => {
  const isMount = useRef(true);
  useEffect(() => {
    if (isMount.current) {
      isMount.current = false;
      return;
    }
    return fn();
  }, deps);
}
// 用法
useUpdateEffect(() => {
  console.log('更新');
})

思路其实很简单,就是多使用一个默认值为 true 的布尔值变量。我们用它来记录当前是否为第一次执行,如果是,就不执行传入的函数,然后将布尔值设置为 false。

false 代表之后都是第二次第三次的执行,每次都执行传入的函数。

这里我们没有用 useState,因为通过 setState 方法会重新渲染组件。所以我们使用了 useRef,修改它的值不会触发组件的更新。

结尾

自定义 Hook,是一种比组件更小粒度的可复用逻辑组织方式,这也是 React 函数组件带给我们最大的惊喜。为此,我们有必要学习好自定义 Hook。

我是前端西瓜哥,欢迎关注我。

相关文章
|
2月前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
187 2
|
4月前
|
设计模式 存储 前端开发
React开发设计模式及原则概念问题之自定义Hooks的作用是什么,自定义Hooks设计时要遵循什么原则呢
React开发设计模式及原则概念问题之自定义Hooks的作用是什么,自定义Hooks设计时要遵循什么原则呢
|
3月前
|
前端开发
React给antd中TreeSelect组件左侧加自定义图标icon
本文介绍了如何在React中为Ant Design的TreeSelect组件的每个树节点添加自定义图标,并解决了因缺少key属性而导致的警告问题,展示了如何通过递归函数处理treeData数据并为每个节点添加图标。
140 2
React给antd中TreeSelect组件左侧加自定义图标icon
|
3月前
|
前端开发 Python
React技术栈-React路由插件之自定义组件标签
关于React技术栈中React路由插件自定义组件标签的教程。
59 4
React技术栈-React路由插件之自定义组件标签
|
2月前
|
前端开发 JavaScript API
自定义React Hooks综合指南
本文介绍了React Hooks及其在组件开发中的作用,重点讲解了自定义Hook的创建和使用方法。通过实例展示了如何创建`useWindowWidth`、`useFetch`和`useForm`等自定义Hook,并分享了使用自定义Hook的最佳实践。文章强调了自定义Hook在提高代码复用性和组件可维护性方面的重要性。
62 0
|
4月前
|
前端开发 JavaScript
|
4月前
|
前端开发
React 中的 Hook 概念
【8月更文挑战第31天】
39 0
|
5月前
|
前端开发
React useImperativeHandle Hook
【7月更文挑战第1天】React useImperativeHandle Hook
30 3
|
5月前
|
前端开发 JavaScript 数据格式
react18【系列实用教程】Hooks (useState,useReducer,useRef,useEffect,useContext,useMemo,useCallback,自定义 Hook )
react18【系列实用教程】Hooks (useState,useReducer,useRef,useEffect,useContext,useMemo,useCallback,自定义 Hook )
98 1
|
5月前
|
前端开发
Vue3 【仿 react 的 hook】封装 useTitle
Vue3 【仿 react 的 hook】封装 useTitle
54 0