React 自定义 Hook 是一种将组件逻辑封装在可重用函数中的方式,它们提供了一种在不编写类的情况下复用状态逻辑的方式。本文将详细介绍如何自定义封装 hook。 ...
|
在 React 项目中,我们经常会使用到 React 自带的几个内置 Hooks,如 useState,useContext 和useEffect。但有时,我们可能希望有一个特定目的的 Hook :例如获取数据 useData,获取连接 useConnect 等。虽然在 React 中找不到这些 Hooks,但 React 提供了非常灵活的方式让你为自己的需求来创建自己的自定义 Hooks。 如何自定义 Hooks在 React 中你必须遵循以下命名约定:
这个命名约定确保你始终可以查看组件,并了解其状态、效果以及其他 React 特性可能“隐藏”的位置。例如,如果你在组件中看到 getColor() 函数调用,你可以确定它不可能包含 React state,因为其名称不以use开头。但是,像 useStatus() 这样的函数调用很可能包含对其他 Hooks 的调用! 组件之间共享逻辑
自定义 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 叫做 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>
);
}登录后复制 在这个例子中,我们导入了 自定义 Hooks 允许你共享有状态逻辑,而不是状态本身自定义 Hooks 允许共享有状态逻辑,但不能共享状态本身。每个对 Hook 的调用都完全独立于对同一个 Hook 的其他调用。
以上面的 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>
);
}登录后复制 当我们点击 分类功能型 Hooks以实现特定功能或目的,与具体业务无关: 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 允许你在本地存储中存储和检索值。 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];
}登录后复制 业务型 HooksuseFetch该 hook 允许你从 API 中获取数据。 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 允许你管理模态对话框的状态。 //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;登录后复制 在多个 Hook 之间传递信息由于 Hook 本身就是函数,因此我们可以在它们之间传递信息。下面我们以 //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>
...
</>
)
}登录后复制 我们将 用户 id 保存在 const [userId,setUserId] = useState('103')
const userInfo = useUserInfo(userId)登录后复制 此时,我们的 将 event handlers 传递给自定义 Hooks
你可能希望让组件自定义其行为,而不是完全地将逻辑封装 Hooks 中,我们可以通过将 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 ,把 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 接受事件处理程序时,你还可以做一个改进。
在 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
}登录后复制 现在不会在每次重新渲染聊天室组件时进行重新连接。 开源 React Hooks 库
总结自定义 Hooks 可以帮助你迁移到更好的开发范式。通过将一些通用逻辑封装在自定义 Hooks 中,你可以使组件代码保持简洁并专注于核心意图,这有助于减少重复性的代码,并使你的代码更易于维护和更新,从而使你能够更快速地开发新功能。 对于 Effect 而言,这样可以使数据在 Effects 中流动的过程变得非常明确。这让你的组件能够专注于意图,而不是 Effects 的具体实现。当 React 添加新功能时,你可以删除那些 Effects 而不影响任何组件。就像设计系统一样,你可能会发现从应用程序组件中提取常见习惯用法到自定义 Hooks 中是有非常帮助的。这将使你的组件代码专注于意图,并允许你避免频繁编写原始 Effects,这也是 React 开发者所推崇的。 (学习视频分享:编程基础视频) 以上就是深入理解React的自定义Hook的详细内容,更多请关注模板之家(www.mb5.com.cn)其它相关文章! |
