首页 > 其他分享 >react之自定义hooks

react之自定义hooks

时间:2023-07-03 13:00:11浏览次数:46  
标签:const 自定义 hooks react Hook 组件 useUpdateEffect useEffect

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

本文地址

合集地址

任何相对独立、复用性强的逻辑,都可以 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 我们可以主动触发组件更新。
    比如在使用过时数据时:
// 过时数据 
const { data } = useSomeHook();

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

每5秒强制组件一次,保证拿到最新数据。

4、useDebounce

定义

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就会调用一次回调函数,实现了定时执行指定函数的功能。
有任何问题欢迎留言讨论学习

标签:const,自定义,hooks,react,Hook,组件,useUpdateEffect,useEffect
From: https://www.cnblogs.com/chaojilaji/p/17522467.html

相关文章

  • react-native项目启动报错 Error: `fsevents` unavailable (this watcher can only be
    react-native项目启动报错——watchman安装问题(macpro) LookingforJSfilesin/Users/你的名称/Documents/project/文件夹名Loadingdependencygraph.../Users/你的名称/Documents/project/文件夹名/node_modules/metro/node_modules/sane/src/fsevents_watcher.js:37......
  • ES 中文分词器ik及自定义远程词库
    ik分词器安装部署 下载地址:https://github.com/medcl/elasticsearch-analysis-ik注意es和ik分词器的版本匹配.这里下载7.9.3的ik分词器下载完毕之后去es的工作目录的plugins文件夹下新建ik文件夹,将下载下来的ik压缩包解压缩至ik文件夹下,重启e   词库介绍ik分词器主......
  • react项目webpack打包图片名去除hash
    环境:node-vv16.16.01、露出webpack配置文件:yarnruneject如果git报错,请执行gitadd.gitcommit-m'ddd'再执行yarnruneject2、执行完上一步后,项目会新增一个config文件夹 修改config\webpack.config.js 修改图片:搜索media,一般在218行出现:“assetModule......
  • 自定义MultipleViewResolver
    1.MultipleViewResolver.javaimportjava.util.Locale;importjava.util.Map;importorg.springframework.web.servlet.View;importorg.springframework.web.servlet.ViewResolver;publicclassMultipleViewResolverimplementsViewResolver{privateMap<St......
  • React - 14 Hooks组件之useRef
    1.获取元素的3种方式方式1:ref={x=>refName=x}函数组件中没有this,直接给了一个变量。(可以用但是不推荐)方式2React.createRef()方式3useRef(null)2.函数组件用useRef,类组件用React.createRefimportReact,{useState,useEffect,useRef}from"react";import{Butto......
  • 11.9 自定义异常
    demo在项目开发中,会大量接触自定义异常本节案例,综合本章节很多案例。classBombExceptionextendsException{//自定义强制处理异常 publicBombException(Stringmsg){ super(msg);//调用父类构造 }}classFood{ publicstaticvoideat(intnum)throwsBombE......
  • 将MembershipCreateStatus枚举成员翻译成自定义信息
    publicstaticclassAccountValidation{publicstaticstringErrorCodeToString(MembershipCreateStatuscreateStatus){switch(createStatus){caseMembershipCreateStatus.DuplicateUserName:......
  • 前端Vue自定义注册界面模版 手机号邮箱账号输入框 验证码输入框  包含手机号邮箱账号
    前端Vue自定义注册界面模版手机号邮箱账号输入框验证码输入框 包含手机号邮箱账号验证,下载完整代码请访问uni-app插件市场地址:https://ext.dcloud.net.cn/plugin?id=13306效果图如下:......
  • 压 力测试系统,支持自定义接口
    短信压力测试系统,支持自定义接口支持卡密,短信压力测试系统,解决一切骚扰电话,教程在压缩包里面可多个服务器挂脚本分担压力,套了cdn导致无法正常执行脚本可以尝试添加白名单这边建议使用MySQL方式同服务器下直接配置数据库信息即可,其他配置详见源码www.httple.net/149170.htm......
  • Qt/C++编写超精美自定义控件(历时9年更新迭代/超202个控件/祖传原创)
    一、前言无论是哪一门开发框架,如果涉及到UI这块,肯定需要用到自定义控件,越复杂功能越多的项目,自定义控件的数量就越多,最开始的时候可能每个自定义控件都针对特定的应用场景,甚至里面带了特定的场景的一些设置和处理,随着项目数量的增多,有些控件又专门提取出来共性,做成了通用的自定义......