首页
开发技巧正文内容

10个React项目自定义Hooks

2024年02月27日
阅读时长 2 分钟
阅读量 64
10个React项目自定义Hooks

在本文中,我们将深入探讨自定义Hooks的世界,探讨它们的重要性,并提供具体的示例,展示如何利用它们来简化和增强React开发。

什么是自定义Hook?

React中的自定义Hook是一个利用一个或多个内置Hook(如useState、useEffect、useContext等)的JavaScript函数。

自定义Hook提供了一种在React组件之间提取和共享逻辑的方式,促进了更清晰的代码、更好的组织和更高的生产力。

在React中创建自定义Hook遵循一组特定的规则和语法。

  1. 自定义Hook应始终以单词"use"开头,以遵循React设定的约定。例如,用于处理表单输入的自定义Hook可以命名为"useFormInput"。

  2. 自定义Hook可以利用useState、useEffect、useContext和其他内置Hook。它们还可以包含任何必要的自定义逻辑,以封装和抽象复杂的功能。

  3. 自定义Hook的主要目标是可重用性。它应该被设计为在应用程序的多个组件中使用,允许您抽象和共享常见的逻辑。

  4. 自定义Hook不应包含任何JSX或导致组件渲染。它们的目的是封装逻辑和状态管理,而不是定义UI。

10个有用的自定义Hook列表:

1. useFocus Hook

import { useRef, useCallback } from "react";

export const useFocus = () => {
  const ref = useRef(null);

  const focusElement = useCallback(() => {
    if (ref.current) {
      ref.current.focus();
    }
  }, []);

  return [ref, focusElement];
};

export default function App() {
  const [inputRef, focusInput] = useFocus();

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <div>
        <input ref={inputRef} type="text" />
        <button onClick={focusInput}>Focus Input</button>
      </div>
    </div>
  );
}

在这个例子中,useFocus自定义Hook返回一个包含ref和函数的数组ref用于存储对DOM元素的引用,focusElement函数用于在调用时将焦点放在该元素上

2. useDelay Hook

import { useState, useEffect } from "react";

export const useDelay = (delayTime) => {
  const [done, setDone] = useState(false);

  useEffect(() => {
    const delay = setTimeout(() => {
      setDone(true);
    }, delayTime);

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

  return done;
};

export default function App() {
  const isDone = useDelay(2000);

  return (
    <div>
      {isDone ? (
        <p>Welcome to JavaScript Centric!</p>
      ) : (
        <p>Page is Loading ...</p>
      )}
    </div>
  );
}

在这个例子中,useDelay Hook在App组件中使用,以引入1000毫秒的延迟。根据延迟是否完成,组件呈现不同的内容。

3. useWindowSize Hook

import { useState, useEffect } from "react";

export const useWindowSize = () => {
  const [windowSize, setWindowSize] = useState({
    width: window.innerWidth,
    height: window.innerHeight,
  });

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

    window.addEventListener("resize", handleResize);

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

  return windowSize;
};

export default function App() {
  const { width, height } = useWindowSize();

  return (
    <div>
      <p>Window Width: {width}</p>
      <p>Window Height: {height}</p>
    </div>
  );
}

在这个例子中,useWindowSize Hook在App组件中使用,以跟踪窗口的尺寸并在组件中显示它们。这个useWindowSize自定义Hook封装了跟踪窗口尺寸的逻辑,使其在不同的组件中可重用,并促进了更具响应性和适应性的用户界面。

4. useOnClickOutside Hook

import React, { useRef, useEffect } from "react";

export const useOnClickOutside = (ref, handler) => {
  useEffect(() => {
    const listener = (event) => {
      if (!ref.current || ref.current.contains(event.target)) {
        return;
      }
      handler(event);
    };

    document.addEventListener("mousedown", listener);
    return () => {
      document.removeEventListener("mousedown", listener);
    };
  }, [ref, handler]);
};

export default function App() {
  const ref = useRef(null);

  const onClose = () => {
    alert("clicked outside");
  };

  useOnClickOutside(ref, onClose);

  return <div ref={ref}>Click outside this element to close</div>;
}

5. useFormUpdate Hook

import React, { useState, useEffect } from "react";

export const useFormUpdate = () => {
  const [isFormUpdated, setIsFormUpdated] = useState(false);

  useEffect(() => {
    const handleBeforeUnload = (event) => {
      if (isFormUpdated) {
        const message =
          "You have unsaved changes. Are you sure you want to leave?";
        event.returnValue = message;
        return message;
      }
    };

    window.addEventListener("beforeunload", handleBeforeUnload);

    return () => {
      window.removeEventListener("beforeunload", handleBeforeUnload);
    };
  }, [isFormUpdated]);

  const handleFormUpdate = () => {
    setIsFormUpdated(true);
  };

  useEffect(() => {
    const formElements = document.querySelectorAll(
      "form input, form select, form textarea"
    );
    const handleFieldChange = () => {
      setIsFormUpdated(true);
    };

    formElements.forEach((element) => {
      element.addEventListener("change", handleFieldChange);
    });

    return () => {
      formElements.forEach((element) => {
        element.removeEventListener("change", handleFieldChange);
      });
    };
  }, []);

  return handleFormUpdate;
};

export default function App() {
  useFormUpdate();

  return (
    <form>
      <input type="text" />
      <input type="email" />
      <textarea />
      <select>
        <option value="1">Option 1</option>
        <option value="2">Option 2</option>
      </select>
      <input type="submit" value="Submit" />
    </form>
  );
}

在这个例子中,useFormUpdate Hook在App组件中使用,自动监视所有表单字段的更改,包括输入、文本区域和选择元素。当用户修改任何表单字段时,表单被标记为已更新,并且当用户尝试导航到未保存的更改时,beforeunload事件监听器被触发。

6. useFetch Hook

import React, { useState, useEffect } from "react";

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

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch(url);
        if (!response.ok) {
          throw new Error("Network response was not ok");
        }
        const result = await response.json();
        setData(result);
      } catch (error) {
        setError(error);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, [url]);

  return { data, loading, error };
};

export default function App() {
  const users = useFetch("https://jsonplaceholder.typicode.com/users");
  return (
    <div>
      {users.loading ? (
        <p>Loading...</p>
      ) : users.error ? (
        <p>Error: {users.error.message}</p>
      ) : (
        <ul>
          {users.data.map((user) => (
            <li key={user.id}>{user.name}</li>
          ))}
        </ul>
      )}
    </div>
  );
}

7. useDebounce Hook

import React, { useState, useEffect } from "react";

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

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

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

  return debouncedValue;
};

export default function App() {
  const [inputValue, setInputValue] = useState("");
  const debouncedValue = useDebounce(inputValue, 500);

  const handleInputChange = (event) => {
    setInputValue(event.target.value);
  };

  return (
    <div>
      <input type="text" value={inputValue} onChange={handleInputChange} />
      <p>Debounced value: {debouncedValue}</p>
    </div>
  );
}

在这个例子中,useDebounce Hook用于防抖动文本输入字段的输入值。在指定的延迟之后,debouncedValue会更新,使您能够更高效地处理输入更改,例如用于实时搜索功能。

8. useLocalStorage Hook

import React, { useState, useEffect } from "react";

export const useLocalStorage = (key, initialValue) => {
  const [storedValue, setStoredValue] = useState(() => {
    try {
      const item = window.localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      console.error(error);
      return initialValue;
    }
  });

  const setValue = (value) => {
    try {
      const valueToStore =
        value instanceof Function ? value(storedValue) : value;
      setStoredValue(valueToStore);
      console.log("valueToStore", valueToStore);
      window.localStorage.setItem(key, JSON.stringify(valueToStore));
    } catch (error) {
      console.error(error);
    }
  };```javascript
useEffect(() => {
    const handleStorageChange = () => {
      try {
        const item = window.localStorage.getItem(key);
        setStoredValue(item ? JSON.parse(item) : initialValue);
      } catch (error) {
        console.error(error);
      }
    };

    window.addEventListener("storage", handleStorageChange);

    return () => {
      window.removeEventListener("storage", handleStorageChange);
    };
  }, [key, initialValue]);

  return [storedValue, setValue];
};

export default function App() {
  const [token, setToken] = useLocalStorage("tokenName", "");
  console.log("token", token);

  const handleTokenChange = (event) => {
    setToken(event.target.value);
  };

  return (
    <div>
      <input type="text" value={token} onChange={handleTokenChange} />
    </div>
  );
}

在这个例子中,useLocalStorage hook 在 App 组件中被使用来持久化和获取与 "tokenName" 键相关联的值。该组件渲染一个输入框,允许用户更新持久化的值。

9. useMediaQuery Hook

import React, { useState, useEffect } from "react";

export const useMediaQuery = (query) => {
  const [matches, setMatches] = useState(false);

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

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

    mediaQuery.addListener(handleMediaQueryChange);
    setMatches(mediaQuery.matches);

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

  return matches;
};

export default function App() {
  const isMobile = useMediaQuery("(max-width: 768px)");

  return <div>{isMobile ? <p>移动端视图</p> : <p>桌面端视图</p>}</div>;
}

在这个例子中,useMediaQuery hook 在 App 组件中被使用来检测基于指定媒体查询的视口大小的变化。该组件根据 useMediaQuery hook 返回的 isMobile 状态有条件地渲染内容。

10. useToggle Hook

import React, { useState } from "react";

export const useToggle = (defaultValue) => {
  const [value, setValue] = useState(defaultValue);

  function toggleValue(value) {
    setValue((currentValue) =>
      typeof value === "boolean" ? value : !currentValue
    );
  }

  return [value, toggleValue];
};

export default function App() {
  const [value, toggleValue] = useToggle(false);

  return (
    <div>
      <div>{value.toString()}</div>
      <button onClick={toggleValue}>切换</button>
      <button onClick={() => toggleValue(true)}>设为真</button>
      <button onClick={() => toggleValue(false)}>设为假</button>
    </div>
  );
}

在这个例子中,useToggle hook 在 App 组件中被使用来在 true 和 false 之间切换一个值。

免责声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

相关文章

探索多种软件架构模式及其实用应用
2024年11月22日19:06
本文深入探讨了多种软件架构模式,包括有界上下文、边车模式、发布-订阅模式、应用网关、微服务、命令职责分离(CQRS)等,介绍了它们的优点、使用场景以及具体应用实例。文章强调根据具体项目需求和团队能力选择最合适的架构,以构建高效和可维护的解决方案,同时展示了各架构模式间的综合应用,提供了丰富的案例和技术细节。
15个高级Python快捷键助您更快编程
2024年11月21日07:02
本文分享了 15 个高级的 Python 编程快捷键,包括上下文管理器、行内字典合并、函数参数解包、链式比较、dataclasses、海象运算符、反转列表、备忘录缓存、splitlines、enumerate、字典推导、zip 用于并行迭代、itertools.chain 扁平化列表、functools.partial 部分函数和 os.path 文件路径管理等,帮助开发者提高编程效率和代码简洁性。
揭示网页开发的 11 个迷思:停止相信这些误区
2024年11月19日22:05
网页开发充满误解,这篇博文针对11个常见迷思进行揭秘。包括网站开发后不需更新、需掌握所有技术、AI会取代开发者等。强调持续学习、专业化、用户体验的重要性,澄清误区如多任务处理的必要性和最新技术的必需性。文章提醒开发者注重实用而非追求完美代码,以务实态度面对开发工作。
你知道 CSS 的四种 Focus 样式吗?
2024年11月18日21:41
本文介绍了四种 CSS focus 样式::focus、:focus-visible、:focus-within 以及自定义的 :focus-visible-within,帮助提升网站用户体验。:focus 样式应用于被选中元素;:focus-visible 仅在键盘导航时显示;:focus-within 用于父元素;自定义 :focus-visible-within 结合两者效果。合理运用这些样式能使网站更方便键盘用户导航。
利用 Python 实现自动化图像裁剪:简单高效的工作流程
2024年11月11日20:49
使用 Python 和 OpenCV 自动裁剪图像,轻松实现 16:9 的完美构图。这个指南介绍了如何通过代码进行灰度化、模糊处理和边缘检测,最终识别出最重要的部分进行裁剪。特别适合需要批量处理图像的情况,节省大量时间。
每位资深前端开发人员都应了解的 TypeScript 高级概念
2024年11月11日02:07
资深前端开发者应了解 TypeScript 的高级概念,如联合类型、交叉类型、类型保护、条件类型、映射类型、模板字面量类型和递归类型。这些特性可提升代码的可维护性和可扩展性,确保在开发复杂应用时实现更高的类型安全性和效率。