自定义 Hooks 的核心是共享组件之间的逻辑。使用自定义 Hooks 能够减少重复的逻辑,更重要的是,自定义 Hooks 内部的代码描述了它们想做什么,而不是如何做。当你将逻辑提取到自定义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 叫做 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 允许共享有状态逻辑,但不能共享状态本身。每个对 Hook 的调用都完全独立于对同一个 Hook 的其他调用。
以上面的 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>
);
}
当我们点击 Increment2
时,并不会影响 count1
,因为每一个 useCounter
的调用都是独立的,其内部状态也是独立的。
以实现特定功能或目的,与具体业务无关:
该 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;
}
该 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];
}
该 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 };
}
该 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 本身就是函数,因此我们可以在它们之间传递信息。下面我们以 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>
...
</>
)
}
我们将 用户 id 保存在 userId
状态变量中,当用户进行某一操作 setUserId
时,由于 useState
为我们提供了 userId
状态变量的最新值,因此我们可以将它作为参数传递给自定义的 useUserInfo
Hook:
const [userId,setUserId] = useState('103')
const userInfo = useUserInfo(userId)
此时,我们的 userInfo
会随着 userId 的改变而更新。
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('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的自定义Hook的详细内容,更多请关注编程网其它相关文章!
--结束END--
本文标题: 深入理解React的自定义Hook
本文链接: https://lsjlt.com/news/207710.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2023-05-25
2023-05-25
2023-05-25
2023-05-25
2023-05-25
2023-05-24
2023-05-24
2023-05-24
2023-05-24
2023-05-24
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0