目錄
如何自訂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