React中怎么自定义Hook

发布时间:2023-04-21 14:21:35 作者:iii
来源:亿速云 阅读:155

这篇文章主要讲解了“React中怎么自定义Hook”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“React中怎么自定义Hook”吧!

如何自定义 Hooks

在 React 中你必须遵循以下命名约定:

这个命名约定确保你始终可以查看组件,并了解其状态效果以及其他 React 特性可能“隐藏”的位置。例如,如果你在组件中看到 getColor() 函数调用,你可以确定它不可能包含 React state,因为其名称不以use开头。但是,像 useStatus() 这样的函数调用很可能包含对其他 Hooks 的调用!

组件之间共享逻辑

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

自定义 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 允许你共享有状态逻辑,而不是状态本身

自定义 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 的调用都是独立的,其内部状态也是独立的。

分类

功能型 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];
}

业务型 Hooks

useFetch

该 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 获取用户信息 为例:

//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 的改变而更新。

将 event handlers 传递给自定义 Hooks

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
}

现在不会在每次重新渲染聊天室组件时进行重新连接。

开源 React Hooks 库

感谢各位的阅读,以上就是“React中怎么自定义Hook”的内容了,经过本文的学习后,相信大家对React中怎么自定义Hook这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!

推荐阅读:
  1. react native生命周期实例分析
  2. 在React怎么实现AJAX请求

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

react hook

上一篇:MongoDB中find操作符怎么使用

下一篇:Python图像处理库crop函数thumbnail方法怎么使用

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》