目录
如何自定义 Hooks
组件之间共享逻辑
自定义 Hooks 允许你共享有状态逻辑,而不是状态本身
分类
功能型 Hooks
useWindowWidth
useLocalStorage
业务型 Hooks
useFetch
useModal
在多个 Hook 之间传递信息
将 event handlers 传递给自定义 Hooks
开源 React Hooks 库
总结
首页 web前端 js教程 深入理解React的自定义Hook

深入理解React的自定义Hook

Apr 20, 2023 pm 06:22 PM
前端 react.js 代码规范

深入理解React的自定义Hook

在 React 项目中,我们经常会使用到 React 自带的几个内置 Hooks,如 useState,useContext 和useEffect。但有时,我们可能希望有一个特定目的的 Hook :例如获取数据 useData,获取连接 useConnect 等。虽然在 React 中找不到这些 Hooks,但 React 提供了非常灵活的方式让你为自己的需求来创建自己的自定义 Hooks。

如何自定义 Hooks

在 React 中你必须遵循以下命名约定:

  • React Component: React 组件名称必须以大写字母开头,如 StatusBar 和 SaveButton。React组件还需要 返回 一些React知道如何渲染的东西,比如 JSX

  • React Hook: Hook 名必须以 use 开头,后面跟着一个大写字母,比如 useState (内置)或useStatus (自定义)。与 React 组件不同的是自定义 Hook 可以返回任意值

这个命名约定确保你始终可以查看组件,并了解其状态效果以及其他 React 特性可能“隐藏”的位置。例如,如果你在组件中看到 getColor() 函数调用,你可以确定它不可能包含 React state,因为其名称不以use开头。但是,像 useStatus() 这样的函数调用很可能包含对其他 Hooks 的调用!

组件之间共享逻辑

The code inside them describes what they want to do rather than how to do it .

自定义 Hooks 的核心是共享组件之间的逻辑。使用自定义 Hooks 能够减少重复的逻辑,更重要的是,自定义 Hooks 内部的代码描述了它们想做什么,而不是如何做。当你将逻辑提取到自定义Hooks 中时,你可以隐藏如何处理某些"外部系统"或浏览器 API 的调用的细节,组件的代码表达的是你的意图,而不是实现细节。 下面是一个简单的例子:

import { useState } from 'react';
function useCounter(initialValue) {
  const [count, setCount] = useState(initialValue);
  function increment() {
    setCount(count + 1);
  }
  return [count, increment];
}
登录后复制

这个自定义 Hook 叫做 useCounter,它接受一个初始值作为参数,并返回一个数组,包含当前的计数值和一个增加计数的函数。 使用自定义 Hook 非常简单,只需要在函数组件中调用它即可。下面是一个使用 useCounter 的例子:

import React from 'react';
import useCounter from './useCounter';

function Counter() {
  const [count, increment] = useCounter(0);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
    </div>
  );
}
登录后复制

在这个例子中,我们导入了 useCounter,并在组件中调用它。我们将返回的数组解构为 count 和 increment,然后在组件中使用它们。

自定义 Hooks 允许你共享有状态逻辑,而不是状态本身

自定义 Hooks 允许共享有状态逻辑,但不能共享状态本身。每个对 Hook 的调用都完全独立于对同一个 Hook 的其他调用。 以上面的 useCounter 为例:

import useCounter from &#39;./useCounter&#39;;
function Counter() {
	const [count1, increment1] = useCounter(0);
	const [count2, increment2] = useCounter(100);
  return (
    <div>
      <p>Count1: {count1}</p>
      <button onClick={increment1}>Increment1</button>
       <p>Count2: {count2}</p>
      <button onClick={increment2}>Increment2</button>
    </div>
  );
}
登录后复制

当我们点击 Increment2 时,并不会影响 count1 ,因为每一个 useCounter 的调用都是独立的,其内部状态也是独立的。

分类

功能型 Hooks

以实现特定功能或目的,与具体业务无关:

useWindowWidth

该 hook 返回窗口宽度的值。

import { useState, useEffect } from &#39;react&#39;;
function useWindowWidth() {
  const [windowWidth, setWindowWidth] = useState(window.innerWidth);
  useEffect(() => {
    const handleResize = () => setWindowWidth(window.innerWidth);
    window.addEventListener(&#39;resize&#39;, handleResize);
    return () => window.removeEventListener(&#39;resize&#39;, handleResize);
  }, []);
  return windowWidth;
}
登录后复制

useLocalStorage

该 hook 允许你在本地存储中存储和检索值。

import { useState } from &#39;react&#39;;

function useLocalStorage(key, initialValue) {
  const [storedValue, setStoredValue] = useState(() => {
    try {
      const item = window.localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      console.log(error);
      return initialValue;
    }
  });

  const setValue = (value) => {
    try {
      setStoredValue(value);
      window.localStorage.setItem(key, JSON.stringify(value));
    } catch (error) {
      console.log(error);
    }
  };

  return [storedValue, setValue];
}
登录后复制

业务型 Hooks

useFetch

该 hook 允许你从 API 中获取数据。

import { useState, useEffect } from &#39;react&#39;;
function useFetch(url) {
  const [data, setData] = useState(null);
  const [error, setError] = useState(null);
  const [isLoading, setIsLoading] = useState(true);
  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch(url);
        const json = await response.json();
        setData(json);
      } catch (error) {
        setError(error);
      } finally {
        setIsLoading(false);
      }
    };
    fetchData();
  }, [url]);
  return { data, error, isLoading };
}
登录后复制

useModal

该 hook 允许你管理模态对话框的状态。

//useFetch.js
import {useState, useEffect} from &#39;react&#39;
//don&#39;t forget to give a url parameter for the function.
const useFetch = (url)=>{
  const [data, setData] = useState([])
  const getData = async ()=>{
    const response = await fetch(url)
    const userdata = await response.json()
    setData(userdata)
  }
 useEffect(()=>{
    getData()
  },[url])
  //return data that we will need in other components.
  return {data};
}
export default useFetch;
登录后复制

在多个 Hook 之间传递信息

由于 Hook 本身就是函数,因此我们可以在它们之间传递信息。下面我们以 useUserInfo 获取用户信息 为例:

//useUserInfo.jsx
import { useEffect,useState } from &#39;react&#39;
const useUserInfo = (userId) => {
  const [userInfo, setUserInfo] = useState({})
  useEffect(() => {
    fetch(&#39;/user&#39;)
      .then(res => res.json())
      .then(data => setUserInfo(data))
  }, [userId])
  return userInfo
}
//Home.jsx
...
const Home = ()=>{
	const [userId,setUserId] = useState(&#39;103&#39;)
	const useInfo = useUserInfo(userId)
	return (
	  <>
	     <div>name:{userInfo.name}</div>
	     <div>age:{userInfo.age}</div>
	     ...
	  </> 
	)
}
登录后复制

我们将 用户 id 保存在 userId 状态变量中,当用户进行某一操作 setUserId 时,由于 useState 为我们提供了 userId 状态变量的最新值,因此我们可以将它作为参数传递给自定义的 useUserInfo Hook:

const [userId,setUserId] = useState(&#39;103&#39;)
const userInfo = useUserInfo(userId)
登录后复制

此时,我们的 userInfo 会随着 userId  的改变而更新。

将 event handlers 传递给自定义 Hooks

This section describes an experimental API that has not yet been released  in a stable version of React. 本节描述了一个尚未在 React 稳定版本中发布的 实验性 API。

你可能希望让组件自定义其行为,而不是完全地将逻辑封装 Hooks 中,我们可以通过将 event handlers 作为参数传递给 Hooks,下面是一个聊天室的例子:useChatRoom 接受一个服务端 url 和 roomId,当调用这个 Hook 的时候,会进行连接,

export function useChatRoom({ serverUrl, roomId }) {
  useEffect(() => {
    const options = {
      serverUrl: serverUrl,
      roomId: roomId
    };
    const connection = createConnection(options);
    connection.connect();
    connection.on(&#39;message&#39;, (msg) => {
      showNotification(&#39;New message: &#39; + msg);
    });
    return () => connection.disconnect();
  }, [roomId, serverUrl]);
}
登录后复制

假设当连接成功时,你想将此逻辑移回你的组件:

export default function ChatRoom({ roomId }) {
  const [serverUrl, setServerUrl] = useState(&#39;https://localhost:1234&#39;);
  useChatRoom({
    roomId: roomId,
    serverUrl: serverUrl,
    onReceiveMessage(msg) {
      showNotification(&#39;New message: &#39; + msg);
    }
  });
  // ...
登录后复制

要做到这一点,改变你的自定义 Hook ,把 onReceiveMessage 作为它的命名选项之一:

export function useChatRoom({ serverUrl, roomId, onReceiveMessage }) {
  useEffect(() => {
    const options = {
      serverUrl: serverUrl,
      roomId: roomId
    };
    const connection = createConnection(options);
    connection.connect();
    connection.on(&#39;message&#39;, (msg) => {
      onReceiveMessage(msg);
    });
    return () => connection.disconnect();
  }, [roomId, serverUrl, onReceiveMessage]); // ✅ All dependencies declared
}
登录后复制

这可以工作,但是当你的自定义 Hook 接受事件处理程序时,你还可以做一个改进。 在 onReceiveMessage 上添加依赖并不理想,因为它会导致每次组件重新渲染时聊天都重新连接。将此事件处理程序包装到 EffectEvent 中以将其从依赖项中移除:

import { useEffect, useEffectEvent } from &#39;react&#39;;  
// ...
export function useChatRoom({ serverUrl, roomId, onReceiveMessage }) {
  const onMessage = useEffectEvent(onReceiveMessage);
  useEffect(() => {
    const options = {
      serverUrl: serverUrl,
      roomId: roomId
    };
    const connection = createConnection(options);
    connection.connect();
    connection.on(&#39;message&#39;, (msg) => {
      onMessage(msg);
    });
    return () => connection.disconnect();
  }, [roomId, serverUrl]); // ✅ All dependencies declared
}
登录后复制

现在不会在每次重新渲染聊天室组件时进行重新连接。

开源 React Hooks 库

  • ahooks 一套由阿里巴巴开源的 React Hooks 库,封装了大量好用的 Hooks。
  • react-use 一个必不可少的 React Hooks 集合。其包含了传感器、用户界面、动画效果、副作用、生命周期、状态这六大类的Hooks。
  • useHooks 一组易于理解的 React Hook集合。
  • react-recipes 一个包含流行的自定义 Hook 的 React Hooks 实用程序库。
  • Rhooks  一组基本的 React 自定义Hooks。
  • react-hanger 一组有用的 hooks,用于特定于某些基本类型的状态更改辅助函数。
  • Beautiful React Hook 一组漂亮的(希望有用的)React hooks 来加速你的组件和 hooks 开发。
  • Awesome React Hooks 一个很棒的 React Hooks 资源集合,该集合包含React Hooks教程、视频、工具,Hooks列表。其中Hooks列表中包含了众多实用的自定义Hooks。
  • SWR 一个用于获取数据的 React Hooks 库。只需一个Hook,就可以显着简化项目中的数据获取逻辑。
  • React Hook Form 一个用于表单状态管理和验证的 React Hooks (Web + React Native)。

总结

自定义 Hooks 可以帮助你迁移到更好的开发范式。通过将一些通用逻辑封装在自定义 Hooks 中,你可以使组件代码保持简洁专注于核心意图,这有助于减少重复性的代码,并使你的代码更易于维护更新,从而使你能够更快速地开发新功能。

对于 Effect 而言,这样可以使数据在 Effects 中流动的过程变得非常明确。这让你的组件能够专注于意图,而不是 Effects 的具体实现。当 React 添加新功能时,你可以删除那些 Effects 而不影响任何组件。就像设计系统一样,你可能会发现从应用程序组件中提取常见习惯用法到自定义 Hooks 中是有非常帮助的。这将使你的组件代码专注于意图,并允许你避免频繁编写原始 Effects,这也是 React 开发者所推崇的。

(学习视频分享:编程基础视频

以上是深入理解React的自定义Hook的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
4 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

PHP与Vue:完美搭档的前端开发利器 PHP与Vue:完美搭档的前端开发利器 Mar 16, 2024 pm 12:09 PM

PHP与Vue:完美搭档的前端开发利器在当今互联网高速发展的时代,前端开发变得愈发重要。随着用户对网站和应用的体验要求越来越高,前端开发人员需要使用更加高效和灵活的工具来创建响应式和交互式的界面。PHP和Vue.js作为前端开发领域的两个重要技术,搭配起来可以称得上是完美的利器。本文将探讨PHP和Vue的结合,以及详细的代码示例,帮助读者更好地理解和应用这两

前端面试官常问的问题 前端面试官常问的问题 Mar 19, 2024 pm 02:24 PM

在前端开发面试中,常见问题涵盖广泛,包括HTML/CSS基础、JavaScript基础、框架和库、项目经验、算法和数据结构、性能优化、跨域请求、前端工程化、设计模式以及新技术和趋势。面试官的问题旨在评估候选人的技术技能、项目经验以及对行业趋势的理解。因此,应试者应充分准备这些方面,以展现自己的能力和专业知识。

Django是前端还是后端?一探究竟! Django是前端还是后端?一探究竟! Jan 19, 2024 am 08:37 AM

Django是一个Python编写的web应用框架,它强调快速开发和干净方法。尽管Django是一个web框架,但是要回答Django是前端还是后端这个问题,需要深入理解前后端的概念。前端是指用户直接和交互的界面,后端是指服务器端的程序,他们通过HTTP协议进行数据的交互。在前端和后端分离的情况下,前后端程序可以独立开发,分别实现业务逻辑和交互效果,数据的交

C#开发经验分享:前端与后端协同开发技巧 C#开发经验分享:前端与后端协同开发技巧 Nov 23, 2023 am 10:13 AM

作为一名C#开发者,我们的开发工作通常包括前端和后端的开发,而随着技术的发展和项目的复杂性提高,前端与后端协同开发也变得越来越重要和复杂。本文将分享一些前端与后端协同开发的技巧,以帮助C#开发者更高效地完成开发工作。确定好接口规范前后端的协同开发离不开API接口的交互。要保证前后端协同开发顺利进行,最重要的是定义好接口规范。接口规范涉及到接口的命

Go语言前端技术探秘:前端开发新视野 Go语言前端技术探秘:前端开发新视野 Mar 28, 2024 pm 01:06 PM

Go语言作为一种快速、高效的编程语言,在后端开发领域广受欢迎。然而,很少有人将Go语言与前端开发联系起来。事实上,使用Go语言进行前端开发不仅可以提高效率,还能为开发者带来全新的视野。本文将探讨使用Go语言进行前端开发的可能性,并提供具体的代码示例,帮助读者更好地了解这一领域。在传统的前端开发中,通常会使用JavaScript、HTML和CSS来构建用户界面

Java开发中如何进行代码文档的编写和维护 Java开发中如何进行代码文档的编写和维护 Oct 10, 2023 pm 08:22 PM

Java开发中如何进行代码文档的编写和维护在Java开发过程中,代码的文档编写和维护是非常重要的一部分。一个好的代码文档可以提高代码的可读性和可维护性,方便项目成员之间的协作和沟通,同时也有助于后期代码的维护和迭代。注释的使用注释是代码文档的基础,它可以用来解释代码的作用、实现逻辑、参数说明等。在Java中,有三种注释形式:单行注释(//)、多行注释(/.

前端怎么实现即时通讯 前端怎么实现即时通讯 Oct 09, 2023 pm 02:47 PM

实现即时通讯的方法有WebSocket、Long Polling、Server-Sent Events、WebRTC等等。详细介绍:1、WebSocket,它可以在客户端和服务器之间建立持久连接,实现实时的双向通信,前端可以使用 WebSocket API来创建WebSocket连接,并通过发送和接收消息来实现即时通讯;2、Long Polling,是一种模拟实时通信的技术等等

Golang与前端技术结合:探讨Golang如何在前端领域发挥作用 Golang与前端技术结合:探讨Golang如何在前端领域发挥作用 Mar 19, 2024 pm 06:15 PM

Golang与前端技术结合:探讨Golang如何在前端领域发挥作用,需要具体代码示例随着互联网和移动应用的快速发展,前端技术也愈发重要。而在这个领域中,Golang作为一门强大的后端编程语言,也可以发挥重要作用。本文将探讨Golang如何与前端技术结合,以及通过具体的代码示例来展示其在前端领域的潜力。Golang在前端领域的作用作为一门高效、简洁且易于学习的

See all articles