React Hooks 简介 1. 使用 Hooks 做好准备

2025-05-26

React hooks 的强大功能

介绍

1. 利用钩子设置舞台

介绍

这不仅仅是一篇 Hooks 和 context 教程,而是我即将撰写一篇关于如何像专业人士一样使用 React Hooks 和状态管理的文章。内容可能有点难以消化,所以赶紧拿起你最喜欢的零食开始吧。
这将是一个由三篇文章组成的系列,它们将提升你的 React Hooks 和状态技能,就像我写这篇文章时一样。如果你想阅读长篇文章,请点击链接。

稍等一下,如果您不了解React HooksReact context API的基础知识,我强烈建议您先了解它们。

1. 利用钩子设置舞台

我们已经使用 React 的新功能组件和钩子有一段时间了,但是你们中有多少人已经意识到钩子的实际威力?

首先,我们将研究自定义钩子可能适用的一些地方以及如何实现它。

1.1 基本useDarkMode钩子

作为程序员,我们喜欢深色主题,但并非所有人都喜欢,所以我们需要在应用中设置一些主题状态。
我们将使用window.matchMedia来匹配CSS 媒体查询,即prefers-color-scheme: dark。这将告诉我们用户的系统主题是否为深色,并作为我们的初始状态。

const matchDark = '(prefers-color-scheme: dark)'

const useDarkMode = () => {
  const [isDark, setIsDark] = useState(() => {
    if (process.browser) {
      return window.matchMedia && window.matchMedia(matchDark).matches
    }
    return false
  })

  return isDark
}

export default useDarkMode
Enter fullscreen mode Exit fullscreen mode

1.2 使其useDarkMode真正有用

现在有些人……他们就是搞不定要用亮色主题还是暗色主题,所以就把主题设成了自动。现在,我们必须在应用程序中考虑到这一点。
我们可以附加一个监听器,window.matchMedia监听主题何时发生变化。
现在,在代码中实现这个功能……

const matchDark = '(prefers-color-scheme: dark)'

const useDarkMode = () => {
  const [isDark, setIsDark] = useState(() => {
    if (process.browser) {
      return window.matchMedia && window.matchMedia(matchDark).matches
    }
    return false
  })

  useEffect(() => {
    const matcher = window.matchMedia(matchDark)
    const onChange = ({ matches }: MediaQueryListEvent) => setIsDark(matches)
    matcher.addListener(onChange)
    return () => {
      matcher.removeListener(onChange)
    }
  }, [setIsDark])

  return isDark
}

export default useDarkMode
Enter fullscreen mode Exit fullscreen mode

现在如何使用这个钩子看起来就像

import useDarkMode from "@hooks/useDarkMode";

const App = () => {
    const theme = useDarkMode() ? themes.dark : themes.light;

    return (
        <ThemeProvider value={theme}>
            ...
        </ThemeProvider>
    )
}
Enter fullscreen mode Exit fullscreen mode

现在,拍拍自己的肩膀!您已经创建了一个有用的自定义钩子。

1.3 最需要的钩子useInView

我们经常需要的另一个功能是检测元素是否在视图中。这时,我们大多数人会尝试使用库来实现这一点,但这比看起来要简单得多。

如何做到这一点很简单:

  1. 我们监听窗口上的滚动
  2. 我们获取元素的边界客户端矩形,以获取其与顶部的偏移量
  3. 我们检查(元素距离顶部的偏移量 + 元素的高度)是否 > 0,以及元素距离顶部的偏移量是否 < 窗口的高度,如果两者都为真,那么我们的元素是可见的。
  4. 如果状态不正确,那么我们设置状态并调用 onChange 函数(如果存在)。
const useInView = (
  elRef: MutableRefObject<HTMLElement | null>,
  onChange?: (_inView: boolean) => void
) => {
  const [inView, setInView] = useState(false)

  useEffect(() => {
    const onScroll = () => {
      if (!elRef.current) return

      const boundingRect = elRef.current.getBoundingClientRect()
      const elementHeight = elRef.current.offsetHeight
      const offsetTop = boundingRect.top
      const windowHeight = window.innerHeight
      const isVisible =
        offsetTop + elementHeight > 0 && offsetTop < windowHeight
      if (isVisible && !inView) {
        setInView(isVisible)
        onChange && onChange(isVisible)
      } else if (!isVisible && inView) {
        setInView(isVisible)
        onChange && onChange(isVisible)
      }
    }

    window.addEventListener('scroll', onScroll)
    return () => {
      window.removeEventListener('scroll', onScroll)
    }
  }, [elRef, onChange, inView])

  return inView
}
Enter fullscreen mode Exit fullscreen mode

使用这个钩子就像创建它一样简单

import React, { useRef } from 'react'

import useInView from '@hooks/useInView'

const Hooks = () => {
  const elementRef = useRef<HTMLDivElement>(null)
    // use as a variable
    const inView = useInView(elementRef)
    // or use a callback
    useInView(elementRef, (isInView) => {
        console.log(isInView ? 'element has appeared' : 'element has disappeared');
    })

  return (
    <div className="w-full max-w-screen-md">
      <div className="h-screen"></div>
      <div
        ref={elementRef}
        className={`py-6 text-center ${
          inView ? 'bg-blue-100' : 'bg-red-100'
        }`}>
        Is in view: {inView ? 'true' : 'false'}
      </div>
      <div className="h-screen"></div>
    </div>
  )
}

export default Hooks
Enter fullscreen mode Exit fullscreen mode

现在你大概已经能想象到 Hooks 的各种用途了。下一部分,我们将探讨如何在 React 应用中轻松管理状态,同时又不失理智。

文章来源:https://dev.to/patheticgeek/react-hooks-on-steroids-48l3
PREV
我创建了一个 App Store
NEXT
规划我的2021年职业发展