5 分钟学会 React Hooks 它们是什么? 👟 useState 为什么不使用 class? 📗 其他 Hooks useEffect 关注点分离 创建自定义 Hooks 注意事项 👍 注意事项 👎 注意事项 ⚠️ 就是这样!

2025-06-07

5分钟学会 React Hooks

这些是什么?

跳进去👟

useState

为什么不上课?📗

其他钩子

useEffect

关注点分离

创建自定义钩子

应该做的事👍

注意事项👎

注意事项⚠️

就是这样!

这些是什么?

一组函数,为我们在实例上访问的方法提供直接 API Component。我们可以创建有状态组件,或者在没有实例的情况下访问组件的生命周期class🎉

对于那些TL;DR阵营的人来说,向下滚动查看一系列演示👍

跳进去👟

考虑一下这个选择并显示颜色值的应用程序🎨

选择更新标签内容的元素

我们需要一个class实例来添加state

const colors = {
  Sea: '#a2ccb6',
  Sand: '#fc22b5',
  Peach: '#ee786e',
}

class App extends Component {
  state = {
    color: colors.Sea,
  }
  render = () => {
    const { color } = this.state
    return (
      <Fragment>
        <select
          value={color}
          onChange={e => this.setState({color: e.target.value})}
          >
          { Object.entries(colors).map(c => (
            <option key={`color--${c[0]}`} value={c[1]}>
              {c[0]}
            </option>
          ))}
        </select>
        <h2>{`Hex: ${color}`}</h2>
      </Fragment>
    )
  }
}
Enter fullscreen mode Exit fullscreen mode

但带钩子

const { useState } = React
const App = () => {
  const [color, setColor] = useState(colors.Sea)
  return (
    <Fragment>
      <select value={color} onChange={e => setColor(e.target.value)}>
        {Object.entries(colors).map(([name, value]) => (
          <option value={value}>{name}</option>
        ))}
      </select>
      <h1>{`Hex: ${color}`}</h1>
    </Fragment>
  )
}
Enter fullscreen mode Exit fullscreen mode

useState是一个允许我们使用和更新状态值的钩子。

useState

useState钩子提供了一个状态值以及更新它的方法。参数是默认值。该值也可以是任意类型!👍

不需要class实例🙌

不要害怕这种语法。useState利用Array解构。

它等于

const state = useState(Colors.Sea)
const color = state[0]
const setColor = state[1]
Enter fullscreen mode Exit fullscreen mode

为什么不上课?📗

  • 缩小效果并不好。
  • 当课程试图承担过多内容时,就会失去背景。
  • 生命周期方法中的关注点分离不佳。
  • 需要对属性进行不稳定的语法转换class
  • HMR 问题。
  • 主观用例,何时使用而不是无状态函数。

如果课程适合您,则无需更改。Hooks 不会取代课程。

其他钩子

有几种钩子。你可能最常使用的钩子是useStateuseEffect。其他钩子请参阅钩子参考

useEffect

当我们想要进入生命周期阶段时,我们会使用这个钩子。

useEffect === componentDidMount + componentDidUpdate + componentWillUnmount
Enter fullscreen mode Exit fullscreen mode

我们将一个函数传递给useEffect在每次渲染上运行的钩子。

让我们使用 来更新我们之前的颜色选择应用程序useEffect

const App = () => {
  const [color, setColor] = useState(colors.Sea)
  useEffect(
    () => {
      document.body.style.background = color
    }
  )
  return (
    <Fragment>
      <select value={color} onChange={e => setColor(e.target.value)}>
        {Object.entries(colors).map(([name, value]) => (
          <option key={`color--${name}`} value={value}>
            {name}
          </option>
        ))}
      </select>
      <h1>{color}</h1>
    </Fragment>
  )
}

Enter fullscreen mode Exit fullscreen mode

现在当状态更新时,主体颜色将会改变👍

选择改变背景颜色的元素

每次渲染都会运行?没错。不过,它并非必须如此。 有一个可选的第二个参数useEffect。您可以传递一个Array值,如果这些值在渲染期间没有变化,则效果将不会执行。空Array表示效果只运行一次。但在大多数情况下,有更好的解决方案来实现这个结果,

useEffect(
  () => {
    document.body.style.background = color
  },
  [color]
)
Enter fullscreen mode Exit fullscreen mode

现在我们只在发生变化时设置背景color👍在这个例子中,它仍然会运行每个渲染,因为这color是触发渲染的唯一事物。

如果我们有第二个状态值,我们就能看到这个可选参数的实际作用。让我们添加一个在按钮点击时递增的计数器值。

const App = () => {
  const [color, setColor] = useState(colors.Sea)
  const [count, setCount] = useState(0)
  // Only run when color is updated 👍
  useEffect(
    () => {
      console.info('Color changed')
      document.body.style.background = color
    },
    [color]
  )
  return (
    <Fragment>
      <select value={color} onChange={e => setColor(e.target.value)}>
        {Object.entries(colors).map(([name, value]) => (
          <option key={`color--${name}`} value={value}>
            {name}
          </option>
        ))}
      </select>
      <h1>{color}</h1>
      <h1>{`Count: ${count}`}</h1>
      <button onClick={() => setCount(count + 1)}>Increment Count</button>
    </Fragment>
  )
}
Enter fullscreen mode Exit fullscreen mode

console.info仅当颜色改变时才会触发👍

其他效果(例如发出 API 请求或绑定用户输入)怎么样?

让我们制作一个跟踪鼠标移动的小应用程序。

鼠标在屏幕上移动并更新屏幕上的位置标签

我们利用useEffect绑定鼠标移动来更新一些状态值。

const App = () => {
  const [x, setX] = useState()
  const [y, setY] = useState()
  useEffect(
    () => {
      const update = (e) => {
        setX(e.x)
        setY(e.y)
      }
      window.addEventListener('mousemove', update)
    },
    []
  )
  return x && y ? (<h1>{`x: ${x}; y: ${y};`}</h1>) : null
}
Enter fullscreen mode Exit fullscreen mode

如果组件卸载了,该如何清除绑定?我们可以从useEffect函数中返回一个函数来进行清理。

useEffect(
  () => {
    const update = (e) => {
      setX(e.x)
      setY(e.y)
    }
    window.addEventListener('mousemove', update)
    return () => {
      window.removeEventListener('mousemove', update)
    }
  },
  []
)
Enter fullscreen mode Exit fullscreen mode

不错👊

关注点分离

钩子使我们能够更好地分离关注点。

您是否曾经见过class似乎有很多事情要做的生命周期方法?

componentDidMount = () => {
  makeSomeAPIRequest()
  makeOtherAPIRequest()
  bindTouchListener()
  bindClickEvents()
  doOtherUnrelatedStuff()
}
Enter fullscreen mode Exit fullscreen mode

我们可以用钩子来避免这种情况。只要我们的钩子位于顶层,我们就可以随意使用。

考虑更新我们的应用,使其也监听resize事件。我们不需要在我们的mousemove效果中实现这一点。我们可以创建一个单独的效果。这是一个值得养成的好习惯,尤其是在我们开始创建自定义钩子的时候。

const App = () => {
  const [dimensions, setDimensions] = useState(getDimensions())
  const [x, setX] = useState()
  const [y, setY] = useState()
  // Effect for mousemove
  useEffect(
    () => {
      const update = e => {
        setX(e.x)
        setY(e.y)
      }
      window.addEventListener('mousemove', update)
      return () => {
        window.removeEventListener('mousemove', update)
      }
    },
    []
  )
  // Effect for window resizing
  useEffect(
    () => {
      const updateSize = () => setDimensions(getDimensions())
      window.addEventListener('resize', updateSize)
      return () => {
        window.removeEventListener('resize', updateSize)
      }
    },
    []
  )
  return (
    <Fragment>
      {x && y && <h1>{`x: ${x}; y: ${y};`}</h1>}
      <h1>
        {`Height: ${dimensions.height}; Width: ${dimensions.width};`}
      </h1>
    </Fragment>
  )
}
Enter fullscreen mode Exit fullscreen mode

这是一个演示👍

创建自定义钩子

最后一个示例中的组件开始增长了。Hook 最棒的特性之一就是我们可以将其用法提取到自定义 hooks 中。

这是 Hooks 的一大卖点。你可能对 props 很熟悉Higher Order Componentsrender我们经常需要某种难以维护或论证的结构或风格。但使用 Hooks 则不会出现这种情况。

考虑一下我们的例子。在我们的应用中,跟踪鼠标移动可能很常见。共享这种逻辑是理想的选择。那就开始吧!

const useMousePosition = () => {
  const [x, setX] = useState()
  const [y, setY] = useState()
  useEffect(
    () => {
      const update = e => {
        setX(e.x)
        setY(e.y)
      }
      window.addEventListener('mousemove', update)
      return () => {
        window.removeEventListener('mousemove', update)
      }
    },
    []
  )
  return { x, y }
}
Enter fullscreen mode Exit fullscreen mode

注意我们新的自定义钩子是如何返回当前状态值的。现在任何组件都可以使用这个自定义钩子来获取鼠标位置。

const App = () => {
  const { x, y } = useMousePosition()
  return x && y ? <h1>{`x: ${x}; y: ${y};`}</h1> : null
}
Enter fullscreen mode Exit fullscreen mode

现在我们有了可以在其他组件之间共享的逻辑💪

让我们考虑另一个例子。我们有各种各样的手表。它们看起来不同,但都使用相同的时间⌚️我们可以自定义一个钩子来获取时间。以下是一个例子;

应该做的事👍

  • 当你需要连接到状态或生命周期阶段时使用
  • 使用钩子分离关注点

注意事项👎

  • 在循环中使用
  • 将它们嵌套
  • 根据条件使用它们。

注意事项⚠️

就是这样!

5 分钟介绍 React Hooks!

进一步了解➡️

获取所有代码➡️

一如既往,如果您有任何问题或建议,请随时留言或发推文给我🐦!记得在社交媒体上关注我!😎

文章来源:https://dev.to/jh3y/react-hooks-in-5-minutes-55ic
PREV
三分钟掌握 React Portals 它是什么?为什么?如何使用?何时使用?作用域 + 冒泡 基本示例(模态框) 一个简单示例 注释 就是这样!
NEXT
5 分钟了解 JavaScript 的 Async + Await