React プロジェクトでは、useState、useContext、useEffect など、React に付属するいくつかの組み込みフックをよく使用します。ただし、特定の目的を持つフックが必要になる場合もあります。たとえば、データを取得するために useData を使用したり、接続を取得するために useConnect を使用したりするなどです。これらのフックは React にはありませんが、React はニーズに合わせて独自のカスタム フックを作成するための非常に柔軟な方法を提供します。
フックをカスタマイズする方法React では、次の命名規則に従う必要があります: で始まる文字。 React コンポーネントは、 JSX など、React がレンダリング方法を認識しているものを return する必要もあります。
で始まり、その後に 大文字 が続く必要があります (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];
}
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>
);
}
をインポートし、コンポーネント内で呼び出しました。返された配列を count
と increment
に分解し、コンポーネントで使用します。
カスタム フックを使用すると、ステートフル ロジックを共有できますが、状態自体は共有できません。 カスタム フックを使用すると、ステートフル ロジックを共有できますが、状態自体は共有できません。フックへの各呼び出しは、同じフックへの他の呼び出しから完全に独立しています。
上記の
useCounter
を例に挙げます。 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;">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>
);
}</pre><div class="contentsignin">ログイン後にコピー</div></div>
には影響しません。 useCounter への呼び出しはすべて独立しており、内部状態も独立しています。
機能フック
特定のビジネスに関係なく、特定の機能または目的を達成するには:
useWindowWidth
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; }
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]; }
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 }; }
//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;
useUserInfo
を使用してユーザー情報を取得します://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> ... </> ) }
userId
状態変数に保存します。ユーザーが特定の操作を実行したときuseState は
userId
useUserInfo に渡すことができます。フック :
const [userId,setUserId] = useState('103') 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('message', (msg) => { showNotification('New message: ' + msg); }); return () => connection.disconnect(); }, [roomId, serverUrl]); }
假设当连接成功时,你想将此逻辑移回你的组件:
export default function ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); useChatRoom({ roomId: roomId, serverUrl: serverUrl, onReceiveMessage(msg) { showNotification('New message: ' + msg); } }); // ...
要做到这一点,改变你的自定义 Hook ,把 onReceiveMessage
作为它的命名选项之一:
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 }
这可以工作,但是当你的自定义 Hook 接受事件处理程序时,你还可以做一个改进。
在 onReceiveMessage
上添加依赖并不理想,因为它会导致每次组件重新渲染时聊天都重新连接。将此事件处理程序包装到 EffectEvent
中以将其从依赖项中移除:
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 }
现在不会在每次重新渲染聊天室组件时进行重新连接。
自定义 Hooks 可以帮助你迁移到更好的开发范式。通过将一些通用逻辑封装在自定义 Hooks 中,你可以使组件代码保持简洁并专注于核心意图,这有助于减少重复性的代码,并使你的代码更易于维护和更新,从而使你能够更快速地开发新功能。
对于 Effect 而言,这样可以使数据在 Effects 中流动的过程变得非常明确。这让你的组件能够专注于意图,而不是 Effects 的具体实现。当 React 添加新功能时,你可以删除那些 Effects 而不影响任何组件。就像设计系统一样,你可能会发现从应用程序组件中提取常见习惯用法到自定义 Hooks 中是有非常帮助的。这将使你的组件代码专注于意图,并允许你避免频繁编写原始 Effects,这也是 React 开发者所推崇的。
(学習ビデオの共有: 基本プログラミング ビデオ)
以上がReact のカスタムフックについての深い理解の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。