欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解React自定義Hook

 更新時(shí)間:2023年04月21日 11:55:34   作者:Aphelios_  
在React項(xiàng)目中,我們經(jīng)常會(huì)使用到React自帶的幾個(gè)內(nèi)置Hooks,如 useState,useContext和useEffect。雖然在React中找不到這些 Hooks,但React提供了非常靈活的方式讓你為自己的需求來(lái)創(chuàng)建自己的自定義Hooks,想了解更多的,歡迎閱讀本文

前言

在 React 項(xiàng)目中,我們經(jīng)常會(huì)使用到 React 自帶的幾個(gè)內(nèi)置 Hooks,如 useState,useContext 和useEffect。但有時(shí),我們可能希望有一個(gè)特定目的的 Hook :例如獲取數(shù)據(jù) useData,獲取連接 useConnect 等。雖然在 React 中找不到這些 Hooks,但 React 提供了非常靈活的方式讓你為自己的需求來(lái)創(chuàng)建自己的自定義 Hooks。

如何自定義 Hooks

在 React 中你必須遵循以下命名約定:

  • React Component: React 組件名稱(chēng)必須以大寫(xiě)字母開(kāi)頭,如 StatusBar 和 SaveButton。React組件還需要 返回 一些React知道如何渲染的東西,比如 JSX 。

  • React Hook: Hook 名必須以 use 開(kāi)頭,后面跟著一個(gè)大寫(xiě)字母,比如 useState (內(nèi)置)或useStatus (自定義)。與 React 組件不同的是自定義 Hook 可以返回任意值

這個(gè)命名約定確保你始終可以查看組件,并了解其狀態(tài)效果以及其他 React 特性可能“隱藏”的位置。例如,如果你在組件中看到 getColor() 函數(shù)調(diào)用,你可以確定它不可能包含 React state,因?yàn)槠涿Q(chēng)不以u(píng)se開(kāi)頭。但是,像 useStatus() 這樣的函數(shù)調(diào)用很可能包含對(duì)其他 Hooks 的調(diào)用!

組件之間共享邏輯

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

自定義 Hooks 的核心是共享組件之間的邏輯。使用自定義 Hooks 能夠減少重復(fù)的邏輯,更重要的是,自定義 Hooks 內(nèi)部的代碼描述了它們想做什么,而不是如何做。當(dāng)你將邏輯提取到自定義Hooks 中時(shí),你可以隱藏如何處理某些"外部系統(tǒng)"或?yàn)g覽器 API 的調(diào)用的細(xì)節(jié),組件的代碼表達(dá)的是你的意圖,而不是實(shí)現(xiàn)細(xì)節(jié)。 下面是一個(gè)簡(jiǎn)單的例子:

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

這個(gè)自定義 Hook 叫做 useCounter,它接受一個(gè)初始值作為參數(shù),并返回一個(gè)數(shù)組,包含當(dāng)前的計(jì)數(shù)值和一個(gè)增加計(jì)數(shù)的函數(shù)。 使用自定義 Hook 非常簡(jiǎn)單,只需要在函數(shù)組件中調(diào)用它即可。下面是一個(gè)使用 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>
  );
}

在這個(gè)例子中,我們導(dǎo)入了 useCounter,并在組件中調(diào)用它。我們將返回的數(shù)組解構(gòu)為 count 和 increment,然后在組件中使用它們。

自定義 Hooks 允許你共享有狀態(tài)邏輯,而不是狀態(tài)本身

自定義 Hooks 允許共享有狀態(tài)邏輯,但不能共享狀態(tài)本身。每個(gè)對(duì) Hook 的調(diào)用都完全獨(dú)立于對(duì)同一個(gè) Hook 的其他調(diào)用。 以上面的 useCounter 為例:

import useCounter from './useCounter';
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>
  );
}

當(dāng)我們點(diǎn)擊 Increment2 時(shí),并不會(huì)影響 count1 ,因?yàn)槊恳粋€(gè) useCounter 的調(diào)用都是獨(dú)立的,其內(nèi)部狀態(tài)也是獨(dú)立的。

分類(lèi)

功能型 Hooks

以實(shí)現(xiàn)特定功能或目的,與具體業(yè)務(wù)無(wú)關(guān):

useWindowWidth

該 hook 返回窗口寬度的值。

import { useState, useEffect } from 'react';
function useWindowWidth() {
  const [windowWidth, setWindowWidth] = useState(window.innerWidth);
  useEffect(() => {
    const handleResize = () => setWindowWidth(window.innerWidth);
    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, []);
  return windowWidth;
}

useLocalStorage

該 hook 允許你在本地存儲(chǔ)中存儲(chǔ)和檢索值。

import { useState } from 'react';

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];
}

業(yè)務(wù)型 Hooks

useFetch

該 hook 允許你從 API 中獲取數(shù)據(jù)。

import { useState, useEffect } from 'react';
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 允許你管理模態(tài)對(duì)話框的狀態(tài)。

//useFetch.js
import {useState, useEffect} from 'react'
//don'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;

在多個(gè) Hook 之間傳遞信息

由于 Hook 本身就是函數(shù),因此我們可以在它們之間傳遞信息。下面我們以 useUserInfo 獲取用戶(hù)信息 為例:

//useUserInfo.jsx
import { useEffect,useState } from 'react'
const useUserInfo = (userId) => {
  const [userInfo, setUserInfo] = useState({})
  useEffect(() => {
    fetch('/user')
      .then(res => res.json())
      .then(data => setUserInfo(data))
  }, [userId])
  return userInfo
}
//Home.jsx
...
const Home = ()=>{
	const [userId,setUserId] = useState('103')
	const useInfo = useUserInfo(userId)
	return (
	  <>
	     <div>name:{userInfo.name}</div>
	     <div>age:{userInfo.age}</div>
	     ...
	  </> 
	)
}

我們將 用戶(hù) id 保存在 userId 狀態(tài)變量中,當(dāng)用戶(hù)進(jìn)行某一操作 setUserId 時(shí),由于 useState 為我們提供了 userId 狀態(tài)變量的最新值,因此我們可以將它作為參數(shù)傳遞給自定義的 useUserInfo Hook:

const [userId,setUserId] = useState('103')
const userInfo = useUserInfo(userId)

此時(shí),我們的 userInfo 會(huì)隨著 userId 的改變而更新。

將 event handlers 傳遞給自定義 Hooks

This section describes an experimental API that has not yet been released in a stable version of React. 本節(jié)描述了一個(gè)尚未在 React 穩(wěn)定版本中發(fā)布的 實(shí)驗(yàn)性 API。

你可能希望讓組件自定義其行為,而不是完全地將邏輯封裝 Hooks 中,我們可以通過(guò)將 event handlers 作為參數(shù)傳遞給 Hooks,下面是一個(gè)聊天室的例子: useChatRoom 接受一個(gè)服務(wù)端 url 和 roomId,當(dāng)調(diào)用這個(gè) Hook 的時(shí)候,會(huì)進(jìn)行連接,

export function useChatRoom({ serverUrl, roomId }) {
  useEffect(() => {
    const options = {
      serverUrl: serverUrl,
      roomId: roomId
    };
    const connection = createConnection(options);
    connection.connect();
    connection.on('message', (msg) => {
      showNotification('New message: ' + msg);
    });
    return () => connection.disconnect();
  }, [roomId, serverUrl]);
}

假設(shè)當(dāng)連接成功時(shí),你想將此邏輯移回你的組件:

export default function ChatRoom({ roomId }) {
  const [serverUrl, setServerUrl] = useState('https://localhost:1234');
  useChatRoom({
    roomId: roomId,
    serverUrl: serverUrl,
    onReceiveMessage(msg) {
      showNotification('New message: ' + msg);
    }
  });
  // ...

要做到這一點(diǎn),改變你的自定義 Hook ,把 onReceiveMessage 作為它的命名選項(xiàng)之一:

export function useChatRoom({ serverUrl, roomId, onReceiveMessage }) {
  useEffect(() => {
    const options = {
      serverUrl: serverUrl,
      roomId: roomId
    };
    const connection = createConnection(options);
    connection.connect();
    connection.on('message', (msg) => {
      onReceiveMessage(msg);
    });
    return () => connection.disconnect();
  }, [roomId, serverUrl, onReceiveMessage]); // ? All dependencies declared
}

這可以工作,但是當(dāng)你的自定義 Hook 接受事件處理程序時(shí),你還可以做一個(gè)改進(jìn)。 在 onReceiveMessage 上添加依賴(lài)并不理想,因?yàn)樗鼤?huì)導(dǎo)致每次組件重新渲染時(shí)聊天都重新連接。將此事件處理程序包裝到 EffectEvent 中以將其從依賴(lài)項(xiàng)中移除:

import { useEffect, useEffectEvent } from 'react';  
// ...
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('message', (msg) => {
      onMessage(msg);
    });
    return () => connection.disconnect();
  }, [roomId, serverUrl]); // ? All dependencies declared
}

現(xiàn)在不會(huì)在每次重新渲染聊天室組件時(shí)進(jìn)行重新連接。

開(kāi)源 React Hooks 庫(kù)

  • ahooks 一套由阿里巴巴開(kāi)源的 React Hooks 庫(kù),封裝了大量好用的 Hooks。
  • react-use 一個(gè)必不可少的 React Hooks 集合。其包含了傳感器、用戶(hù)界面、動(dòng)畫(huà)效果、副作用、生命周期、狀態(tài)這六大類(lèi)的Hooks。
  • useHooks 一組易于理解的 React Hook集合。
  • react-recipes 一個(gè)包含流行的自定義 Hook 的 React Hooks 實(shí)用程序庫(kù)。
  • Rhooks 一組基本的 React 自定義Hooks。
  • react-hanger 一組有用的 hooks,用于特定于某些基本類(lèi)型的狀態(tài)更改輔助函數(shù)。
  • Beautiful React Hook 一組漂亮的(希望有用的)React hooks 來(lái)加速你的組件和 hooks 開(kāi)發(fā)。
  • Awesome React Hooks 一個(gè)很棒的 React Hooks 資源集合,該集合包含React Hooks教程、視頻、工具,Hooks列表。其中Hooks列表中包含了眾多實(shí)用的自定義Hooks。
  • SWR 一個(gè)用于獲取數(shù)據(jù)的 React Hooks 庫(kù)。只需一個(gè)Hook,就可以顯著簡(jiǎn)化項(xiàng)目中的數(shù)據(jù)獲取邏輯。
  • React Hook Form 一個(gè)用于表單狀態(tài)管理和驗(yàn)證的 React Hooks (Web + React Native)。

總結(jié)

自定義 Hooks 可以幫助你遷移到更好的開(kāi)發(fā)范式。通過(guò)將一些通用邏輯封裝在自定義 Hooks 中,你可以使組件代碼保持簡(jiǎn)潔專(zhuān)注于核心意圖,這有助于減少重復(fù)性的代碼,并使你的代碼更易于維護(hù)更新,從而使你能夠更快速地開(kāi)發(fā)新功能。

對(duì)于 Effect 而言,這樣可以使數(shù)據(jù)在 Effects 中流動(dòng)的過(guò)程變得非常明確。這讓你的組件能夠專(zhuān)注于意圖,而不是 Effects 的具體實(shí)現(xiàn)。當(dāng) React 添加新功能時(shí),你可以刪除那些 Effects 而不影響任何組件。就像設(shè)計(jì)系統(tǒng)一樣,你可能會(huì)發(fā)現(xiàn)從應(yīng)用程序組件中提取常見(jiàn)習(xí)慣用法到自定義 Hooks 中是有非常幫助的。這將使你的組件代碼專(zhuān)注于意圖,并允許你避免頻繁編寫(xiě)原始 Effects,這也是 React 開(kāi)發(fā)者所推崇的。

以上就是詳解React自定義Hook的詳細(xì)內(nèi)容,更多關(guān)于React自定義Hook的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論