react之自定义hooks

简介: 任何相对独立、复用性强的逻辑,都可以 extract 为自定义 Hook,自定义 Hook 是一种复用 React 的状态逻辑的函数。

原文合集地址如下,有需要的朋友可以关注

本文地址

合集地址

任何相对独立、复用性强的逻辑,都可以 extract 为自定义 Hook,自定义 Hook 是一种复用 React 的状态逻辑的函数。
自定义 Hook 的主要特点是:

  • 抽象组件间的状态逻辑,方便复用
  • 让功能组件更纯粹,更易于维护
  • 自定义 Hook 可以调用其他 Hook

为什么要用自定义 Hook?

  1. 提炼能复用的逻辑
    许多组件有相似的状态逻辑,使用自定义 Hook 可以很方便地提取出来复用。
  2. 解决复杂组件的可读性问题
    使用自定义 Hook 将复杂组件拆分为更小的功能独立的函数,有助于提高代码的可读性。
  3. 管理数据更新
    使用独立的 Hook 函数来管理数据请求、处理异步逻辑、数据缓存等,易于维护。
  4. 分离状态逻辑
    自定义 Hook 让函数组件更纯粹,只负责 UI,状态逻辑则交给 Hook。
  5. 调用其他 Hook
    自定义 Hook 本身还可以调用 useState、useEffect 等其他 React Hook。

以下是我总结的一些常用的hooks

1、useUpdateEffect

useUpdateEffect作用

useUpdateEffect 是一个自定义的 React Hook,用于在组件更新时执行副作用操作。它类似于 React 的 useEffect,但是会忽略组件的初始渲染阶段,只在组件更新时执行副作用操作。

在 React 中,useEffect 会在组件的每次渲染(包括初始渲染)完成后执行副作用操作。但有时候我们只想在组件更新时执行某些操作,而不关心初始渲染阶段的操作。这就是 useUpdateEffect 的用途。

以下是一个示例:

import { useEffect, useState } from 'react';

function MyComponent() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    console.log('useEffect - Component has rendered');
  });

  useUpdateEffect(() => {
    console.log('useUpdateEffect - Component has updated');
  });

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}

在上述示例中,当点击 "Increment" 按钮时,count 的值会增加并触发组件的重新渲染。useEffect 会在每次渲染后执行,而 useUpdateEffect 只会在组件更新时执行。

通过使用 useUpdateEffect,你可以在组件更新时执行一些特定的副作用操作,如请求数据、更新状态等,而不需要关心初始渲染阶段的操作。

为什么会需要用到useUpdateEffect

在某些情况下,我们希望在 React 组件更新时执行一些特定的副作用操作,而不在初始渲染阶段执行这些操作。这种情况下,我们可以使用类似于 useUpdateEffect 的自定义 Hook。

以下是一些使用 useUpdateEffect 的常见情况:

  1. 避免初始渲染时执行副作用:有些副作用操作可能只需要在组件更新时执行,例如发送网络请求、更新特定状态等。使用 useUpdateEffect 可以确保这些副作用操作在初始渲染时被跳过,只在组件更新时执行。

  2. 监听特定状态的变化:有时我们只关心特定状态的变化,并希望在状态发生变化时执行相应的操作。通过将状态值作为 useUpdateEffect 的依赖项,可以确保副作用操作只在这些状态发生变化时触发。

  3. 更新外部资源或库:有些第三方库或外部资源可能需要在组件更新时进行更新或重新初始化。使用 useUpdateEffect 可以确保在组件更新时调用相应的函数或方法,以便正确地更新这些外部资源。

通过使用 useUpdateEffect,我们可以更加精确地控制副作用操作的触发时机,避免不必要的重复执行,以及在需要时处理特定的更新逻辑。

需要注意的是,React 自带的 useEffect 可以处理大多数情况下的副作用操作,而 useUpdateEffect 是在某些特定场景下的补充工具。在大多数情况下,使用 useEffect 即可满足需求。

自定义useUpdateEffect

要自定义一个类似于 useUpdateEffect 的自定义 Hook,你可以借助 React 的 useEffectuseRef Hooks 来实现。以下是一个示例代码:

import { useEffect, useRef } from 'react';

function useUpdateEffect(effect, dependencies) {
  const isMounted = useRef(false);

  useEffect(() => {
    if (isMounted.current) {
      effect();
    } else {
      isMounted.current = true;
    }
  }, dependencies);
}

// 使用示例
function MyComponent() {
  const [count, setCount] = useState(0);

  useUpdateEffect(() => {
    console.log('Component has updated');
  }, [count]);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}

在上述示例中,我们创建了一个名为 useUpdateEffect 的自定义 Hook。它接受两个参数:effectdependencies。在内部,我们使用了 useRef 来创建一个标记是否已经完成初始渲染的变量 isMounted

useEffect 中,我们检查 isMounted 的值。如果 isMounted 的值为 true,则表示组件已经完成了初始渲染,此时执行传入的 effect 函数。否则,将 isMounted 的值设置为 true,表示组件已完成初始渲染。

在使用时,你可以像使用 useEffect 一样,传入 effect 函数和依赖项数组 dependencies,并且 effect 函数只会在组件更新时执行。

2、useTitle

useTitle 是一个相对经典的自定义 React Hook ,用来控制浏览器标题:

定义useTitle

import {
    useState, useEffect } from 'react';

function useTitle(initialTitle) {
   
  const [title, setTitle] = useState(initialTitle);

  useEffect(() => {
   
    document.title = title;
  }, [title]);

  return setTitle;
}

使用useTitle:

function Page() {
   
  const setTitle = useTitle('Default Title');

  return (
    <Button onClick={
   () => setTitle('New Title')}>
      Click me
    </Button>
  )
}

点击按钮后,浏览器标题会变成"New Title"。
它的工作原理是:

  • 保存标题的 state ,并记录修改 setTitle()
  • 用 useEffect 监测 title 变化,设置 document.title
    所以一旦我们调用 setTitle('New Title') 改变 state ,useEffect 就会执行,设置新的浏览器标题。
    useTitle 的优点是:
  • 抽象出设置标题的逻辑,任何组件都可以共享
  • 让组件更纯粹,只需要调用 setTitle() 接口即可
    我们甚至可以抽象为更通用的 Hook:
js
function useDocumentTitle(title) {
   
  useEffect(() => {
   
    document.title = title;
  }, [title]);
}

function Page() {
   
  useDocumentTitle('Default Title');
  // ...
}

通过自定义 Hook ,可以方便地在任何组件控制标题。

3、useForceUpdate

定义useForceUpdate

import {
    useState } from 'react';

function useForceUpdate() {
   
  const [value, setValue] = useState(0); 

  return () => {
   
    setValue(value => value + 1); 
  };
}

useForceUpdate的使用

const forceUpdate = useForceUpdate();

// 模拟更新组件
forceUpdate();

这个 Hook 返回了一个更新函数。在调用这个函数时,使用useState强制组件重新渲染。
这是基于以下原理实现的:

  • useState()会触发组件重新渲染
  • state变化后,组件函数会重新执行
    函数式组件只有 state 或 props 变化时才会更新。
    使用此 Hook 我们可以主动触发组件更新。
    比如在使用过时数据时:
    ```javascript
    // 过时数据
    const { data } = useSomeHook();

// 更新组件
const forceUpdate = useForceUpdate();
setInterval(() => {
forceUpdate();
}, 5000);

每5秒强制组件一次,保证拿到最新数据。
# 4、useDebounce
## 定义

```javascript
const useDebounce = (value, delay) => {
  const [debouncedValue, setDebouncedValue] = useState(value);

  useEffect(() => {
    const handler = setTimeout(() => {
      setDebouncedValue(value);   
    }, delay);
    return () => {
      clearTimeout(handler); 
    };
  }, []); // 设为空数组[]

  useEffect(() => {
    clearTimeout(handler);     
    handler = setTimeout(() => {
      setDebouncedValue(value);
    }, delay);
  }, [value]);  // 只依赖 value

  return debouncedValue;
};

使用

const inputValue = useDebounced(searchTerm, 500);

这里 每当searchTerm变化时,会设置一个 500ms 的定时器。只有500ms内没有再改变searchTerm,才会更新debouncedValue
这实现了防抖功能:在一定时间内停止触发, 只执行最后的动作。

5、useThrottle

定义

const useThrottle = (value, limit) => {
   
  const [throttledValue, setThrottledValue] = useState(value);

  useEffect(() => {
   
    const handler = setTimeout(() => {
   
      setThrottledValue(value);
    }, limit);
    return () => {
   
      clearTimeout(handler);
    };
  }, []); // 应设为空数组[]  

  useEffect(() => {
   
    clearTimeout(handler);
    handler = setTimeout(() => {
   
      setThrottledValue(value);    
    }, limit);
  }, [value, limit]); 

  return throttledValue;  
};

使用

const throttledValue = useThrottle(inputValue, 1000);

这里 每次inputValue变化时,会开始一个计时器。1s后才会更新throttledValue,实现了节流功能。

6、useInterval

定义

const useInterval = (callback, delay) => {
   
  const savedCallback = useRef();

  useEffect(() => {
   
    savedCallback.current = callback;
  }); 

  useEffect(() => {
   
    function tick() {
   
      savedCallback.current();          
    }
    if (delay !== null) {
   
      let id = setInterval(tick, delay);        
      return () => clearInterval(id);
    }
  }, [delay]);
}

使用

useInterval(() => {
   
  // ...
}, 1000);

这里每1000ms就会调用一次回调函数,实现了定时执行指定函数的功能。
有任何问题欢迎留言讨论学习

目录
相关文章
|
2月前
|
前端开发 测试技术 开发工具
探索前端框架React Hooks的优势与应用
本文将深入探讨前端框架React Hooks的优势与应用。通过分析React Hooks的特性以及实际应用案例,帮助读者更好地理解和运用这一现代化的前端开发工具。
|
3天前
|
JSON 弹性计算 前端开发
函数计算产品使用问题之遇到在自定义运行时部署React项目时遇到样式无法正常加载。一般是什么导致的
函数计算产品作为一种事件驱动的全托管计算服务,让用户能够专注于业务逻辑的编写,而无需关心底层服务器的管理与运维。你可以有效地利用函数计算产品来支撑各类应用场景,从简单的数据处理到复杂的业务逻辑,实现快速、高效、低成本的云上部署与运维。以下是一些关于使用函数计算产品的合集和要点,帮助你更好地理解和应用这一服务。
|
10天前
|
缓存 前端开发 JavaScript
React Hooks 一步到位
React Hooks 一步到位
|
2月前
|
存储 前端开发 JavaScript
React Hooks 的替代方案有哪些?
【5月更文挑战第28天】React Hooks 的替代方案有哪些?
29 2
|
2月前
|
前端开发 JavaScript 开发者
React Hooks 的应用场景有哪些?
【5月更文挑战第28天】React Hooks 的应用场景有哪些?
17 1
|
2月前
|
前端开发 JavaScript 开发者
React Hooks 是在 React 16.8 版本中引入的一种新功能
【5月更文挑战第28天】React Hooks 是在 React 16.8 版本中引入的一种新功能
27 1
|
2月前
|
前端开发
React Hooks - useState 的使用方法和注意事项(1),web前端开发前景
React Hooks - useState 的使用方法和注意事项(1),web前端开发前景
|
2月前
|
前端开发
探索React Hooks:一种全新的组件逻辑管理方式
React Hooks是React 16.8版本引入的一项新功能,它改变了我们编写React组件的方式。本文将从Hooks的起源讲起,逐步分析Hooks的优势,并通过具体示例展示Hooks在组件逻辑管理中的应用,旨在帮助读者更好地理解和运用React Hooks。
|
2月前
|
前端开发 API 开发者
React Hooks API:自定义Hooks的创建与使用
【4月更文挑战第25天】本文介绍了React自定义Hooks的创建与使用。自定义Hooks是提升React开发效率的关键工具。
|
2月前
|
前端开发 数据可视化 API
前端react 18.2整合ckeditor富文本编辑器——配置插件、自定义toolbar工具栏(二)
前端react 18.2整合ckeditor富文本编辑器——配置插件、自定义toolbar工具栏
125 0
前端react 18.2整合ckeditor富文本编辑器——配置插件、自定义toolbar工具栏(二)