Heim > Web-Frontend > js-Tutorial > Detailliertes Verständnis der benutzerdefinierten Hooks von React

Detailliertes Verständnis der benutzerdefinierten Hooks von React

青灯夜游
Freigeben: 2023-04-20 18:22:54
nach vorne
1943 Leute haben es durchsucht

Detailliertes Verständnis der benutzerdefinierten Hooks von React

In React-Projekten verwenden wir häufig mehrere integrierte Hooks, die mit React geliefert werden, wie z. B. useState, useContext und useEffect. Aber manchmal möchten wir vielleicht einen Hook mit einem bestimmten Zweck haben: zum Beispiel useData zum Abrufen von Daten, useConnect zum Abrufen von Verbindungen usw. Obwohl diese Hooks nicht in React zu finden sind, bietet React eine sehr flexible Möglichkeit für Sie, Ihre eigenen benutzerdefinierten Hooks für Ihre Bedürfnisse zu erstellen.

So passen Sie Hooks an

In React müssen Sie die folgende Namenskonvention befolgen:

  • React-Komponente: React Komponentennamen müssen mit Großbuchstaben beginnen, wie z. B. StatusBar und SaveButton. React-Komponenten benötigen außerdem , um etwas zurückzugeben, das React rendern kann, wie z. B. JSX . 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];
}
Nach dem Login kopieren

这个自定义 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>
  );
}
Nach dem Login kopieren

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

自定义 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>
  );
}
Nach dem Login kopieren

当我们点击 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;
}
Nach dem Login kopieren

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];
}
Nach dem Login kopieren

业务型 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 };
}
Nach dem Login kopieren

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;
Nach dem Login kopieren

在多个 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>
	     ...
	  </> 
	)
}
Nach dem Login kopieren

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

const [userId,setUserId] = useState(&#39;103&#39;)
const userInfo = useUserInfo(userId)
Nach dem Login kopieren

此时,我们的 userInfo

React Hook: Der Hook-Name muss mit

beginnen und
verwenden, gefolgt von einem

Großbuchstaben , z. B useState (integriert) oder useStatus (benutzerdefiniert). Im Gegensatz zu React-Komponenten können benutzerdefinierte Hooks jeden Wert

zurückgeben. #🎜🎜##🎜🎜# Diese Namenskonvention stellt sicher, dass Sie die Komponente immer sehen und ihren #🎜🎜# Status #🎜🎜#, #🎜🎜#Auswirkung #🎜🎜# und verstehen können andere #🎜🎜# Orte #🎜🎜#, an denen React-Funktionen möglicherweise „versteckt“ sind. Wenn Sie beispielsweise einen getColor()-Funktionsaufruf in einer Komponente sehen, können Sie sicher sein, dass dieser keinen React-Status enthalten kann, da sein Name nicht mit „use“ beginnt. Funktionsaufrufe wie useStatus() enthalten jedoch wahrscheinlich Aufrufe an andere Hooks! #🎜🎜#

Gemeinsame Logik zwischen Komponenten #🎜🎜##🎜🎜##🎜🎜#Der darin enthaltene Code beschreibt, was sie tun möchten, und nicht, wie es zu tun ist it .#🎜🎜#

#🎜🎜#Der Kern benutzerdefinierter Hooks ist #🎜🎜# gemeinsame Logik zwischen Komponenten #🎜🎜#. Die Verwendung benutzerdefinierter Hooks kann #🎜🎜# sich wiederholende #🎜🎜#-Logik reduzieren. Noch wichtiger ist, dass der Code in benutzerdefinierten Hooks beschreibt, was sie tun möchten, und nicht, wie es zu tun ist. Wenn Sie Logik in benutzerdefinierte Hooks extrahieren, können Sie #🎜🎜# die #🎜🎜# Details darüber ausblenden, wie bestimmte „externe System“- oder Browser-API-Aufrufe #🎜🎜# der Komponente behandelt werden. Der Code drückt Ihre #🎜🎜#Absicht# aus. 🎜🎜#, nicht #🎜🎜#Implementierungsdetails#🎜🎜#. Hier ist ein einfaches Beispiel: #🎜🎜#
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]);
}
Nach dem Login kopieren
Nach dem Login kopieren
#🎜🎜#Dieser benutzerdefinierte Hook heißt useCounter, der einen Anfangswert als Parameter akzeptiert und ein Array zurückgibt, das den aktuellen Zählwert und eine Funktion enthält erhöht die Anzahl. Die Verwendung eines benutzerdefinierten Hooks ist sehr einfach. Rufen Sie ihn einfach in der Funktionskomponente auf. Hier ist ein Beispiel für die Verwendung von useCounter: #🎜🎜#
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);
    }
  });
  // ...
Nach dem Login kopieren
Nach dem Login kopieren
#🎜🎜#In diesem Beispiel haben wir useCounter importiert und in der Komponente aufgerufen. Wir zerlegen das zurückgegebene Array in count und increment und verwenden sie in der Komponente. #🎜🎜#

Benutzerdefinierte Hooks ermöglichen die gemeinsame Nutzung von zustandsbehafteter Logik, jedoch nicht des Zustands selbst. #🎜🎜##🎜🎜# Benutzerdefinierte Hooks ermöglichen die gemeinsame Nutzung von zustandsbehafteter Logik, jedoch nicht des Zustands selbst. Jeder Aufruf an einen Hook ist völlig unabhängig von anderen Aufrufen an denselben Hook. Nehmen Sie den obigen useCounter als Beispiel: #🎜🎜#
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
}
Nach dem Login kopieren
Nach dem Login kopieren
#🎜🎜#Wenn wir auf Increment2 klicken, hat dies keinen Einfluss auf count1, da Each Der Aufruf von useCounter ist unabhängig, und sein interner Status ist ebenfalls unabhängig. #🎜🎜#

Klassifizierung#🎜🎜#

Funktionale Hooks#🎜🎜##🎜🎜# um bestimmte Funktionen oder Zwecke zu erreichen, hat nichts mit dem spezifischen Geschäft zu tun: #🎜🎜#

useWindowWidth#🎜🎜##🎜🎜#Dieser Hook gibt den Wert der Fensterbreite zurück. #🎜🎜#
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
}
Nach dem Login kopieren
Nach dem Login kopieren

useLocalStorage#🎜🎜##🎜🎜#Mit diesem Hook können Sie Werte aus dem lokalen Speicher speichern und abrufen. #🎜🎜#rrreee

Business Hooks#🎜🎜#

useFetch#🎜🎜##🎜🎜#Mit diesem Hook können Sie Get Daten von der API. #🎜🎜#rrreee

useModal#🎜🎜##🎜🎜#Mit diesem Hook können Sie den Status eines modalen Dialogfelds verwalten. #🎜🎜#rrreee

Übergabe von Informationen zwischen mehreren Hooks#🎜🎜##🎜🎜#Da Hooks selbst Funktionen sind, können wir Informationen zwischen ihnen weitergeben. Im Folgenden nehmen wir useUserInfo als Beispiel, um Benutzerinformationen zu erhalten: #🎜🎜#rrreee#🎜🎜#Wir speichern die Benutzer-ID in der Statusvariablen userId, wenn der Benutzer etwas ausführt Eine bestimmte Operation Wenn setUserId, da useState uns den neuesten Wert der Statusvariablen userId liefert, können wir ihn als Parameter an übergeben Benutzerdefinierter useUserInfo-Hook: #🎜🎜#rrreee#🎜🎜#Zu diesem Zeitpunkt wird unser userInfo aktualisiert, wenn sich die Benutzer-ID ändert. #🎜🎜##🎜🎜#Übergabe von Ereignishandlern an benutzerdefinierte Hooks#🎜🎜##🎜🎜##🎜🎜#Dieser Abschnitt beschreibt eine #🎜🎜#experimentelle#🎜🎜# API, die noch nicht in einer stabilen Version veröffentlicht wurde von React. In diesem Abschnitt wird eine experimentelle API beschrieben, die noch nicht in einer stabilen Version von React veröffentlicht wurde. #🎜🎜#

你可能希望让组件自定义其行为,而不是完全地将逻辑封装 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]);
}
Nach dem Login kopieren
Nach dem Login kopieren

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

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);
    }
  });
  // ...
Nach dem Login kopieren
Nach dem Login kopieren

要做到这一点,改变你的自定义 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
}
Nach dem Login kopieren
Nach dem Login kopieren

这可以工作,但是当你的自定义 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
}
Nach dem Login kopieren
Nach dem Login kopieren

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

开源 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 开发者所推崇的。

(Teilen von Lernvideos: Video zu Programmiergrundlagen)

Das obige ist der detaillierte Inhalt vonDetailliertes Verständnis der benutzerdefinierten Hooks von React. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:juejin.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage