React自定义Hook深入解析

React是一个可重复使用的UI组件库,而自定义Hook让我们可以使用自己的逻辑来将一些行为等移到可重复使用的函数中,方便代码的复用和组合。

一、Hook的简介

React Hook是在React16.8版本新增的一项特性。它允许您在不编写 Class 组件的情况下使用状态(state)和其它 React 特性。它们是一个允许您在函数组件中添加状态和其他React功能的方法。

使用hooks,就可以在不编写Class组件的情况下,使用状态(state)等react特性, 无需改变组件的层级,更容易的实现复用和组合。

二、何为自定义Hook?

自定义hook使得你可以使用功能组件实现状态逻辑复用。自定义hook是一个函数,命名以use为前缀,函数内部可以调取别的hook。自定义hook可以将组件的状态逻辑提取到可重用的函数中。


function useCustomHook() {
  //调用state或Effect等hook
  const [count, setCount] = useState(0);
  useEffect(() => {
    //登场效果
  });
  //自定义函数
  function handleCount() {
    setCount(count + 1);
  }
  //返回数据
  return {
    count,
    handleCount,
  };
}
function CustomComponent() {
  //调用自定义hook
  const { count, handleCount } = useCustomHook();
  //返回展示效果
  return (
    <div>
      <p>The count is {count}</p>
      <button onClick={handleCount}>Click me</button>
    </div>
  );
}

三、实现业务逻辑分离

使用自定义hook使得我们可以把共同的业务逻辑放在一起。例如,当我们需要处理本地存储的请求时,无需在每一个需要本地存储的组件重复去写hook获取存储值。

下面是一个实现LocalStorage逻辑分离的例子:


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 {
      const valueToStore =
        value instanceof Function ? value(storedValue) : value;
      setStoredValue(valueToStore);
      window.localStorage.setItem(key, JSON.stringify(valueToStore));
    } catch (error) {
      console.log(error);
    }
  };

  return [storedValue, setValue];
}

function CustomComponent() {
  const [name, setName] = useLocalStorage("name", "");
  //返回展示效果
  return (
    <div>
      <p>My name is {name}</p>
      <button onClick={() => setName("John Doe")}>Set name to John Doe</button>
    </div>
  );
}

四、组件与非组件hook的区别

自定义hook既可以作为组件的hook使用,也可以是非组件的hook。不过对于组件hook与非组件hook在实现上有一定的区别:

  • 组件hook可以依赖参数进行更新,除此之外的非组件hook是用来实现通用逻辑。
  • 组件hook可以返回待渲染的JSX,而非组件hook则是返回状态和操作函数。

//组件hook
function useScrollTop() {
  const [scrollTop, setScrollTop] = useState(false);
  useEffect(() => {
    function handleScroll() {
      setScrollTop(window.scrollY > 0);
    }
    document.addEventListener('scroll', handleScroll);
    return () => {
      document.removeEventListener('scroll', handleScroll);
    }
  }, []);
  return <div style={{ position: 'fixed', top: '18px', right: '30px' }}>{scrollTop&&<a href="#top">UP</a>}</div>;
}

//非组件hook
function useNotification(title, options) {
  if (!("Notification" in window)) {
    return;
  }
  const [permission] = useState(Notification.permission);
  const [notification, setNotification] = useState(null);

  const handleNotification = () => {
    const notification = new Notification(title, options);
    setNotification(notification);
  };

  const checkNotificationPromise = () => {
    try {
      Notification.requestPermission().then();
    } catch (e) {
      return false;
    }
    return true;
  };

  const requestNotificationPermission = async () => {
    if (permission === "granted") {
      handleNotification();
    } else if (permission !== "denied") {
      const permission = await Notification.requestPermission();
      if (permission === "granted") {
        handleNotification();
      }
    }
  };

  useEffect(() => {
    if (permission === "granted") {
      requestNotificationPermission();
    } else if (permission === "default") {
      checkNotificationPromise();
    }
    return () => {
      if (notification) {
        notification.close();
      }
    };
  }, []);
}

五、自定义Hook对流程控制的影响

自定义hook聚焦于某些行为,以让组件对他们进行使用而不需要关心实现细节。自定义hook让组件更容易组合、共享行为,而无需关心时间的实现细节。

而对于每一个使用Effect的组件,都需要在componentDidMount和componentDidUnMount中组合其中的一些行为。这些代码很容易出错、难以阅读、难以恢复,并且难以测试。

自定义Hook让我们可以将这种代码和行为分离,同时让我们的组件不那么臃肿。自定义Hook可以针对一个特定的行为,而不是一个组件,从而更好地实现复用和组合。

六、结语

自定义hook使得我们可以将代码结构更加清晰和易于复用。从我们的应用程序中抽象出类似于useEffect、useState、useRef和useReducer的概念,并使用它们构建更高层次的抽象,可以更好地表达我们的意图,发现隐式复杂性。

在任何情况下,请记住重构代码并不总是意味着把所有东西重新设计到新的地方。根据需要使用自定义hook或者组件可以使代码更易于维护和扩展。

原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/242242.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
小蓝小蓝
上一篇 2024-12-12 12:48
下一篇 2024-12-12 12:48

相关推荐

  • @uiw/react-amap介绍

    本文将详细阐述@uiw/react-amap的使用方法和参数配置,以及如何在React应用中集成高德地图组件。 一、@uiw/react-amap简介 @uiw/react-ama…

    编程 2025-04-29
  • Python中自定义函数必须有return语句

    自定义函数是Python中最常见、最基本也是最重要的语句之一。在Python中,自定义函数必须有明确的返回值,即必须要有return语句。本篇文章将从以下几个方面对此进行详细阐述。…

    编程 2025-04-29
  • Python自定义列表

    本文将为大家介绍Python中自定义列表的方法和应用场景。对自定义列表进行详细的阐述,包括列表的基本操作、切片、列表推导式、列表的嵌套以及列表的排序,希望能够帮助大家更好地理解和应…

    编程 2025-04-27
  • Webrtc音视频开发React+Flutter+Go实战PDF

    本文将从多个方面介绍如何使用React、Flutter和Go来进行Webrtc音视频开发,并提供相应的代码示例。 一、Webrtc音视频开发介绍 Webrtc是Google开发的一…

    编程 2025-04-27
  • 如何添加Python自定义模块?

    Python是一种非常流行的脚本语言,因其易学易用和功能强大而备受欢迎。自定义模块是Python开发中经常使用的功能之一。本文将从多个方面为您介绍如何添加Python自定义模块。 …

    编程 2025-04-27
  • React简书项目

    本文将从以下几个方面介绍React简书项目: 项目概述 组件分析 路由配置 Redux状态管理 项目优化 一、项目概述 React简书项目是一个类似于博客的Web应用,提供用户撰写…

    编程 2025-04-27
  • 深入解析Vue3 defineExpose

    Vue 3在开发过程中引入了新的API `defineExpose`。在以前的版本中,我们经常使用 `$attrs` 和` $listeners` 实现父组件与子组件之间的通信,但…

    编程 2025-04-25
  • 深入理解byte转int

    一、字节与比特 在讨论byte转int之前,我们需要了解字节和比特的概念。字节是计算机存储单位的一种,通常表示8个比特(bit),即1字节=8比特。比特是计算机中最小的数据单位,是…

    编程 2025-04-25
  • 深入理解Flutter StreamBuilder

    一、什么是Flutter StreamBuilder? Flutter StreamBuilder是Flutter框架中的一个内置小部件,它可以监测数据流(Stream)中数据的变…

    编程 2025-04-25
  • 深入探讨OpenCV版本

    OpenCV是一个用于计算机视觉应用程序的开源库。它是由英特尔公司创建的,现已由Willow Garage管理。OpenCV旨在提供一个易于使用的计算机视觉和机器学习基础架构,以实…

    编程 2025-04-25

发表回复

登录后才能评论