React のカスタムフックについての深い理解

青灯夜游
リリース: 2023-04-20 18:22:54
転載
1879 人が閲覧しました

React のカスタムフックについての深い理解

React プロジェクトでは、useState、useContext、useEffect など、React に付属するいくつかの組み込みフックをよく使用します。ただし、特定の目的を持つフックが必要になる場合もあります。たとえば、データを取得するために useData を使用したり、接続を取得するために useConnect を使用したりするなどです。これらのフックは React にはありませんが、React はニーズに合わせて独自のカスタム フックを作成するための非常に柔軟な方法を提供します。

フックをカスタマイズする方法

React では、次の命名規則に従う必要があります:

  • React コンポーネント: React コンポーネント名は ## で大文字にする必要があります。 # StatusBar や SaveButton など、

    で始まる文字。 React コンポーネントは、 JSX など、React がレンダリング方法を認識しているものを return する必要もあります。

  • React フック: フック名は
  • use

    で始まり、その後に 大文字 が続く必要があります (useState (組み込み) や useStatus など)。 (カスタム )。 React コンポーネントとは異なり、カスタム フックは 任意の値を返すことができます

  • この命名規則により、いつでもコンポーネントを表示して、その
ステータス

効果、および「隠されている可能性があるその他の React 機能」を理解できるようになります。 "# ##位置###。たとえば、コンポーネント内に getColor() 関数呼び出しがある場合、名前が use で始まっていないため、そのコンポーネントに React 状態が含まれるはずがないことがわかります。ただし、 useStatus() のような関数呼び出しには、他のフックへの呼び出しが含まれる可能性があります。 コンポーネント間の共有ロジック

コンポーネント内のコードは、

方法ではなく何をしたいかを記述します

.

#カスタムフックの中核は、共有コンポーネント間のロジックです。カスタム フックを使用すると、

反復的な
ロジックを減らすことができます。さらに重要なのは、カスタム フック内のコードは、その実行方法ではなく、何を実行するかを記述していることです。ロジックをカスタム フックに抽出すると、コンポーネントのコードがユーザーの

意図を表現するため、特定の「外部システム」またはブラウザ API への呼び出しを処理する方法の 詳細を隠すことができます。 実装の詳細ではありません。 以下は簡単な例です:

import { useState } from 'react';
function useCounter(initialValue) {
  const [count, setCount] = useState(initialValue);
  function increment() {
    setCount(count + 1);
  }
  return [count, increment];
}
ログイン後にコピー
このカスタム フックは useCounter と呼ばれ、パラメータとして初期値を受け取り、現在のカウント値と増分カウントを含む配列を返します。 。 カスタム フックの使用は非常に簡単で、関数コンポーネントで呼び出すだけです。 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

をインポートし、コンポーネント内で呼び出しました。返された配列を countincrement に分解し、コンポーネントで使用します。

カスタム フックを使用すると、ステートフル ロジックを共有できますが、状態自体は共有できません。 カスタム フックを使用すると、ステートフル ロジックを共有できますが、状態自体は共有できません。フックへの各呼び出しは、同じフックへの他の呼び出しから完全に独立しています。 上記の useCounter を例に挙げます。 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;">import useCounter from &amp;#39;./useCounter&amp;#39;; function Counter() { const [count1, increment1] = useCounter(0); const [count2, increment2] = useCounter(100); return ( &lt;div&gt; &lt;p&gt;Count1: {count1}&lt;/p&gt; &lt;button onClick={increment1}&gt;Increment1&lt;/button&gt; &lt;p&gt;Count2: {count2}&lt;/p&gt; &lt;button onClick={increment2}&gt;Increment2&lt;/button&gt; &lt;/div&gt; ); }</pre><div class="contentsignin">ログイン後にコピー</div></div>

Increment2

をクリックしても、

count1

には影響しません。 useCounter への呼び出しはすべて独立しており、内部状態も独立しています。

カテゴリ

機能フック特定のビジネスに関係なく、特定の機能または目的を達成するには:useWindowWidth

このフックは、ウィンドウの幅の値。

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

このフックを使用すると、ローカル ストレージに値を保存したり、ローカル ストレージから値を取得したりできます。

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];
}
ログイン後にコピー

ビジネス フック

useFetch

このフックを使用すると、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

このフックを使用すると、モーダル ダイアログ ボックスの状態を管理できます。

//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;
ログイン後にコピー

複数のフック間での情報の受け渡し

フック自体は関数なので、フック間で情報を受け渡すことができます。以下では、例として

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

useStateuserId

状態変数の最新の値を提供するため、それをパラメータとしてカスタム

useUserInfo に渡すことができます。フック :

const [userId,setUserId] = useState(&#39;103&#39;)
const userInfo = useUserInfo(userId)
ログイン後にコピー
現時点では、userId の変更に応じて userInfo が更新されます。 イベント ハンドラーをカスタム フックに渡すこのセクションでは、React の安定バージョンではまだリリースされていない

実験的

API について説明します。 このセクションでは、React の安定バージョンではまだリリースされていない実験的な API について説明します。 </blockquote><p>你可能希望让组件自定义其行为,而不是完全地将逻辑封装 Hooks 中,我们可以通过将 <code>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 のカスタムフックについての深い理解の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:juejin.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート