第四章 react 常用Hooks(商业案例)

129 阅读5分钟

1. 异步加载数据Hooks

首先,创建一个名为 AsyncDataLoader.tsx 的文件,其中包含 AsyncDataLoader 组件的代码:

import React from 'react';
import useAsyncData from './useAsyncData'; // 导入自定义 Hookfunction AsyncDataLoader({ fetchFunction, render }) {
  const { data, isLoading, error } = useAsyncData(fetchFunction);
​
  if (isLoading) {
    return (
      <div className="loading-overlay">
        <div className="loading-spinner"></div>
      </div>
    );
  }
​
  if (error) {
    return <div>Error: {error.message}</div>;
  }
​
  return render(data);
}
​
export default AsyncDataLoader;

接下来,创建一个名为 useAsyncData.ts 的文件,其中包含 useAsyncData 自定义 Hook 的代码:

// useAsyncData.js
​
import { useState, useEffect } from 'react';
​
// 自定义 Hook:用于获取异步加载的数据
function useAsyncData(fetchFunction) {
  const [data, setData] = useState(null);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState(null);
​
  useEffect(() => {
    async function fetchData() {
      try {
        setIsLoading(true);
        setError(null);
​
        const result = await fetchFunction();
​
        setData(result);
      } catch (error) {
        setError(error as Error);
      } finally {
        setIsLoading(false);
      }
    }
​
    fetchData();
  }, [fetchFunction]);
​
  return { data, isLoading, error };
}
​
export default useAsyncData;

现在,你可以在主应用文件中导入 AsyncDataLoader 组件并使用它:

import React, {useState, useEffect, FC} from 'react'
// hooks
function useAsyncData (fetchFunction: any) {
    const [data, setData] = useState<null|any>(null)
    const [isLoading, setIsLoading] = useState(true)
    const [error, setError] = useState<null|any>(null)
    useEffect(() => {
        //组件挂载后异步执行
        async function fetchData() {
            try {
                // 设置loading
                setIsLoading(true)
                setError(null)
                const result = await fetchFunction()
                //更新数据
                setData(result)
            } catch(error) {
                setData(error)
            } finally {
                setIsLoading(false)
            }
            
        }
        fetchData()
    },[fetchFunction])
    return {data, isLoading, error}
}
export default useAsyncData

这样,你的组件和自定义 Hook 现在都位于单独的文件中,提高了代码的可读性和维护性,并且使组件可以在应用的不同部分重复使用。希望这对你有所帮助!如果你有其他问题或需要进一步的帮助,请随时提问。

然后,你可以在 AsyncDataLoader.css 文件中定义样式,如下所示:

/* AsyncDataLoader.css *//* 遮罩屏幕 */
.loading-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(255, 255, 255, 0.8);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 9999;
}
​
/* 加载动画 */
.loading-spinner {
  border: 4px solid rgba(255, 255, 255, 0.3);
  border-radius: 50%;
  border-top: 4px solid #007bff;
  width: 40px;
  height: 40px;
  animation: spin 1s linear infinite;
}
​
/* 错误消息 */
.error-message {
  color: red;
}

上面的 CSS 样式定义了遮罩屏幕、加载动画和错误消息的外观。你可以根据需要进行自定义样式。

确保将 AsyncDataLoader.css 文件与 AsyncDataLoader.js 放在同一目录下,以确保样式能够正确加载。

2. useLocalStorage Hook-本地缓存

// hooks/useLocalStorage.jsimport { useState } from 'react';
​
/**
 * @function useLocalStorage
 * @param {string} key - 存储在localStorage中的键名
 * @param {any} initialValue - 初始值
 * @returns {object} - 包含存储值和更新存储值的函数
 */
function useLocalStorage(key, initialValue) {
  // 从localStorage中获取存储值,如果不存在则使用初始值
  const [storedValue, setStoredValue] = useState(() => {
    const item = window.localStorage.getItem(key);
    return item ? JSON.parse(item) : initialValue;
  });
​
  // 更新存储值并同步到localStorage
  const setValue = (value) => {
    setStoredValue(value);
    window.localStorage.setItem(key, JSON.stringify(value));
  };
​
  return [storedValue, setValue];
}
​
export default useLocalStorage;

3. useAuthentication Hook-用户鉴权

// hooks/useAuthentication.jsimport { useState } from 'react';
​
/**
 * @function useAuthentication
 * @returns {object} - 包含用户身份认证状态和登录/注销函数
 */
function useAuthentication() {
  const [authenticated, setAuthenticated] = useState(false);
​
  const login = () => {
    setAuthenticated(true);
  };
​
  const logout = () => {
    setAuthenticated(false);
  };
​
  return { authenticated, login, logout };
}
​
export default useAuthentication;

4.useModal Hook -- 开关状态

import { useState } from 'react';
/**
 * @function useModal
 * @returns {object} - 包含模态框状态和打开/关闭模态框函数
 */
function useModal() {
  const [isOpen, setIsOpen] = useState(false);
​
  const openModal = () => {
    setIsOpen(true);
  };
​
  const closeModal = () => {
    setIsOpen(false);
  };
​
  return { isOpen, openModal, closeModal };
}
​
export default useModal;

5.useNotification Hook --通知消息

// hooks/useNotification.jsimport { useState } from 'react';
​
/**
 * @function useNotification
 * @returns {object} - 包含通知消息和显示/隐藏通知函数
 */
function useNotification() {
  const [message, setMessage] = useState(null);
​
  const showMessage = (text) => {
    setMessage(text);
  };
​
  const hideMessage = () => {
    setMessage(null);
  };
​
  return { message, showMessage, hideMessage };
}
​
export default useNotification;

6. useGeoLocation Hook --地理位置

// hooks/useGeoLocation.js

import { useState, useEffect } from 'react';

/**
 * @function useGeoLocation
 * @returns {object} - 包含地理位置信息和获取地理位置函数
 */
function useGeoLocation() {
  const [location, setLocation] = useState(null);

  useEffect(() => {
    navigator.geolocation.getCurrentPosition((position) => {
      setLocation(position.coords);
    });
  }, []);

  return { location };
}

export default useGeoLocation;

7.useLocalStorageList Hook --缓存列表

// hooks/useLocalStorageList.js

import { useState, useEffect } from 'react';

/**
 * @function useLocalStorageList
 * @param {string} key - 存储在localStorage中的键名
 * @param {array} initialValue - 初始值
 * @returns {object} - 包含列表数据和更新列表数据的函数
 */
function useLocalStorageList(key, initialValue) {
  const [list, setList] = useState(() => {
    const storedList = window.localStorage.getItem(key);
    return storedList ? JSON.parse(storedList) : initialValue;
  });

  useEffect(() => {
    window.localStorage.setItem(key, JSON.stringify(list));
  }, [list, key]);

  const addItem = (item) => {
    setList([...list, item]);
  };

  const removeItem = (index) => {
    const updatedList = [...list];
    updatedList.splice(index, 1);
    setList(updatedList);
  };

  return { list, addItem, removeItem };
}

export default useLocalStorageList;

8.useWebSocket Hook-- 长连接

// hooks/useWebSocket.js

import { useState, useEffect } from 'react';

/**
 * @function useWebSocket
 * @param {string} url - WebSocket连接URL
 * @returns {object} - 包含WebSocket连接状态和消息处理函数
 */
function useWebSocket(url) {
  const [socket, setSocket] = useState(null);

  useEffect(() => {
    const newSocket = new WebSocket(url);

    newSocket.onopen = () => {
      console.log('WebSocket connected');
    };

    newSocket.onmessage = (event) => {
      // 处理接收到的消息
    };

    newSocket.onclose = () => {
      console.log('WebSocket disconnected');
    };

    setSocket(newSocket);

    return () => {
      newSocket.close();
    };
  }, [url]);

  const sendMessage = (message) => {
    if (socket && socket.readyState === WebSocket.OPEN) {
      socket.send(message);
    }
  };

  return { sendMessage };
}

export default useWebSocket;

9.useMediaQuery Hook --媒体查询

javascriptCopy code// hooks/useMediaQuery.js

import { useState, useEffect } from 'react';

/**
 * @function useMediaQuery
 * @param {string} query - 媒体查询字符串
 * @returns {boolean} - 是否匹配媒体查询
 */
function useMediaQuery(query) {
  const [matches, setMatches] = useState(false);

  useEffect(() => {
    const mediaQuery = window.matchMedia(query);
    setMatches(mediaQuery.matches);

    const updateMatches = (event) => {
      setMatches(event.matches);
    };

    mediaQuery.addListener(updateMatches);

    return () => {
      mediaQuery.removeListener(updateMatches);
    };
  }, [query]);

  return matches;
}

export default useMediaQuery;

10. useDebounce Hook --防抖

// hooks/useDebounce.js

import { useState, useEffect } from 'react';

/**
 * @function useDebounce
 * @param {any} value - 要防抖的值
 * @param {number} delay - 防抖延迟时间(毫秒)
 * @returns {any} - 防抖后的值
 */
function useDebounce(value, delay) {
  const [debouncedValue, setDebouncedValue] = useState(value);

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

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

  return debouncedValue;
}

export default useDebounce;

11.useDarkMode Hook --系统模式

// hooks/useDarkMode.js

import { useState, useEffect } from 'react';

/**
 * @function useDarkMode
 * @returns {boolean} - 是否处于暗模式
 */
function useDarkMode() {
  const [isDarkMode, setIsDarkMode] = useState(false);

  useEffect(() => {
    // 根据系统或用户设置来检测暗模式
    const prefersDarkMode = window.matchMedia('(prefers-color-scheme: dark)');
    setIsDarkMode(prefersDarkMode.matches);

    // 监听系统设置的变化
    const darkModeListener = (event) => {
      setIsDarkMode(event.matches);
    };

    prefersDarkMode.addListener(darkModeListener);

    return () => {
      prefersDarkMode.removeListener(darkModeListener);
    };
  }, []);

  return isDarkMode;
}

export default useDarkMode;

12.useProductInventory Hook --库存查询

javascriptCopy code// hooks/useProductInventory.js

import { useState, useEffect } from 'react';

/**
 * @function useProductInventory
 * @param {string} productId - 产品ID
 * @returns {object} - 包含产品库存信息和更新库存的函数
 */
function useProductInventory(productId) {
  const [inventory, setInventory] = useState(0);

  useEffect(() => {
    // 从API获取产品库存信息并更新状态
    const fetchProductInventory = async () => {
      try {
        const response = await fetch(`/api/inventory/${productId}`);
        const data = await response.json();
        setInventory(data.inventory);
      } catch (error) {
        console.error('Error fetching product inventory:', error);
      }
    };

    fetchProductInventory();
  }, [productId]);

  const updateInventory = (newInventory) => {
    setInventory(newInventory);
  };

  return { inventory, updateInventory };
}

export default useProductInventory;

13.useOrderManagement Hook --订单获取

javascriptCopy code// hooks/useOrderManagement.js

import { useState, useEffect } from 'react';

/**
 * @function useOrderManagement
 * @returns {object} - 包含订单列表、创建订单和更新订单状态的函数
 */
function useOrderManagement() {
  const [orders, setOrders] = useState([]);
  
  useEffect(() => {
    // 从API获取订单列表并更新状态
    const fetchOrders = async () => {
      try {
        const response = await fetch('/api/orders');
        const data = await response.json();
        setOrders(data.orders);
      } catch (error) {
        console.error('Error fetching orders:', error);
      }
    };

    fetchOrders();
  }, []);

  const createOrder = (newOrder) => {
    // 创建新订单并更新状态
    // 发送新订单到API
    // 更新状态
  };

  const updateOrderStatus = (orderId, newStatus) => {
    // 更新订单状态并更新状态
    // 发送状态更新到API
    // 更新状态
  };

  return { orders, createOrder, updateOrderStatus };
}

export default useOrderManagement;