重生之我在chatgpt中学习React 第十八天之自定义 Hooks-前端-E先生的博客
Java
MySQL
大数据
Python
前端
黑科技
大语言模型
    首页 >> 互联网 >> 前端

重生之我在chatgpt中学习React 第十八天之自定义 Hooks

[导读]:React 学习指南 - 第十八天 🚀主题:自定义 Hooks(封装可复用逻辑)在 React 中,自定义 Hooks 是一个非常强大的工具,它能让我们复用逻辑,减少代码冗余,提高可读性和维护性。今天,我们将深入学习 如何创建自定义 Hooks,并探讨几个常见的实用场景。1. 为什么需要自定义 Hooks?在开发 React 应用时,我们经常会遇到相...

React 学习指南 - 第十八天 🚀

主题:自定义 Hooks(封装可复用逻辑)

在 React 中,自定义 Hooks 是一个非常强大的工具,它能让我们复用逻辑,减少代码冗余,提高可读性和维护性。今天,我们将深入学习 如何创建自定义 Hooks,并探讨几个常见的实用场景。


1. 为什么需要自定义 Hooks?

在开发 React 应用时,我们经常会遇到相似的逻辑,例如:

  • 获取和存储 localStorage 数据

  • 处理窗口大小、鼠标位置等浏览器事件

  • 请求 API 获取数据

  • 防抖(debounce)和节流(throttle)

如果不使用自定义 Hooks,我们可能会在多个组件中重复编写相同的逻辑,导致代码冗余难以维护
自定义 Hooks 可以将这些逻辑封装起来,使代码更加模块化易读易测试


2. 创建第一个自定义 Hook

自定义 Hooks 本质上就是一个以 use 开头的 JavaScript 函数,它可以使用其他 Hooks,但必须遵循 React Hooks 规则。

示例 1:封装 useLocalStorage

很多应用都需要存储用户偏好(如主题语言)到 localStorage
我们可以创建一个 useLocalStorage Hook 来管理 localStorage 的读写。

import { useState, useEffect } from "react";

function useLocalStorage(key, initialValue) {
  const [value, setValue] = useState(() => {
    // 读取 localStorage
    const storedValue = localStorage.getItem(key);
    return storedValue ? JSON.parse(storedValue) : initialValue;
  });

  useEffect(() => {
    // 更新 localStorage
    localStorage.setItem(key, JSON.stringify(value));
  }, [key, value]);

  return [value, setValue];
}

// 使用自定义 Hook
function App() {
  const [theme, setTheme] = useLocalStorage("theme", "light");

  return (
    <div>
      <p>当前主题:{theme}</p>
      <button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>
        切换主题
      </button>
    </div>
  );
}

export default App;

数据持久化:刷新页面后,theme 仍然保留
封装了 localStorage 逻辑,可以在不同组件复用
useEffect 监听 value 变化,自动更新 localStorage


3. 监听窗口大小:useWindowSize

在响应式设计中,我们可能需要监听窗口大小的变化,并动态调整 UI。

import { useState, useEffect } from "react";

function useWindowSize() {
  const [size, setSize] = useState({
    width: window.innerWidth,
    height: window.innerHeight,
  });

  useEffect(() => {
    const handleResize = () => {
      setSize({ width: window.innerWidth, height: window.innerHeight });
    };

    window.addEventListener("resize", handleResize);
    return () => window.removeEventListener("resize", handleResize);
  }, []);

  return size;
}

// 使用自定义 Hook
function App() {
  const { width, height } = useWindowSize();

  return (
    <div>
      <p>窗口宽度:{width}px</p>
      <p>窗口高度:{height}px</p>
    </div>
  );
}

export default App;

监听 resize 事件,窗口大小变化时自动更新状态
自动解绑事件监听器,避免内存泄漏


4. 获取鼠标位置:useMousePosition

如果我们需要追踪鼠标位置(如画布、游戏、交互组件),可以创建 useMousePosition Hook。

import { useState, useEffect } from "react";

function useMousePosition() {
  const [position, setPosition] = useState({ x: 0, y: 0 });

  useEffect(() => {
    const updateMousePosition = (e) => {
      setPosition({ x: e.clientX, y: e.clientY });
    };

    window.addEventListener("mousemove", updateMousePosition);
    return () => window.removeEventListener("mousemove", updateMousePosition);
  }, []);

  return position;
}

// 使用自定义 Hook
function App() {
  const { x, y } = useMousePosition();

  return (
    <div>
      <p>鼠标位置:X={x}, Y={y}</p>
    </div>
  );
}

export default App;

自动监听鼠标移动,适用于绘图、拖拽、交互组件
自动解绑监听事件,避免性能问题


5. API 请求封装:useFetch

在 React 应用中,我们通常需要请求 API 并管理加载状态和错误处理。
useFetch 可以封装这一逻辑,使其更易复用。

import { useState, useEffect } from "react";

function useFetch(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    setLoading(true);
    fetch(url)
      .then((response) => response.json())
      .then((data) => {
        setData(data);
        setLoading(false);
      })
      .catch((err) => {
        setError(err);
        setLoading(false);
      });
  }, [url]);

  return { data, loading, error };
}

// 使用自定义 Hook
function App() {
  const { data, loading, error } = useFetch("https://jsonplaceholder.typicode.com/posts/1");

  if (loading) return <p>加载中...</p>;
  if (error) return <p>错误:{error.message}</p>;

  return (
    <div>
      <h2>{data.title}</h2>
      <p>{data.body}</p>
    </div>
  );
}

export default App;

封装了 API 请求、加载状态、错误处理
复用性强,适用于所有 API 请求
通过依赖 url 实现自动请求


6. 防抖与节流

防抖(Debounce):useDebounce

防抖用于减少输入频率,例如搜索框防止频繁请求 API

import { useState, useEffect } from "react";

function useDebounce(value, delay) {
  const [debouncedValue, setDebouncedValue] = useState(value);

  useEffect(() => {
    const handler = setTimeout(() => {
      setDebouncedValue(value);
    }, delay);

    return () => clearTimeout(handler);
  }, [value, delay]);

  return debouncedValue;
}

// 使用自定义 Hook
function App() {
  const [query, setQuery] = useState("");
  const debouncedQuery = useDebounce(query, 500);

  useEffect(() => {
    if (debouncedQuery) {
      console.log("搜索:" + debouncedQuery);
    }
  }, [debouncedQuery]);

  return (
    <input 
      type="text" 
      value={query} 
      onChange={(e) => setQuery(e.target.value)} 
      placeholder="输入搜索内容..." 
    />
  );
}

减少 API 请求频率,适用于搜索框、输入框

image.png

本文来自E先生的博客,如若转载,请注明出处:https://javajz.cn

留言区

联系人:
手   机:
内   容:
验证码:

历史留言

欢迎加Easy的QQ