每个初学者都应该知道的2个React钩子

63 阅读5分钟

React Hook是一个JavaScript函数,可以让你从功能组件中 "钩住 "React状态和生命周期特性。它在React 16.8中首次被引入,提供了一个替代编写基于类的组件的方法。虽然传统项目使用类组件,但现代React开发大多使用功能组件,它利用钩子,使开发人员能够编写更清晰、更简洁的代码。

在这篇博文中,我们将介绍两个有用的钩子,每个初学者在第一次学习React时都应该知道。也就是状态钩子和效果钩子,将在下面介绍。

状态钩子

在React中,状态是一个组件中的动态数据。它存储的数据会根据用户与应用程序的交互方式而改变。下面是一个例子,说明在React中如何启动一个状态,以及如何在组件中使用它:

import React, { useState } from 'react';

function Example() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

为了启动React状态,我们首先导入useState函数,然后在传入初始状态(本例中初始值为0)的同时调用该函数。这个函数调用将返回一个有两个元素的数组,第一个是初始状态的值,第二个是用来更新状态的函数。然后,我们对数组进行解构,创建2个新的变量,可以随时用于我们的组件中。count变量包含当前状态,而setCount变量包含更新当前状态的函数。

在这种情况下,我们是通过onClick事件处理程序来更新状态的。每次用户点击按钮,1就会被添加到当前状态中,这个新值会被传递到setCount函数中,该函数会将当前状态更新为新值。因此,在初始状态为0的情况下,点击一次按钮后,当前状态会更新为1,因为1+0=1。一旦状态更新,整个组件就会重新显示,新的状态1将被反映在p标签中并显示给用户。

效果钩子

效果钩子是一个React钩子,当组件渲染时引起一个副作用。它看起来像这样:

import React, { useEffect } from "react";

function DogPics() {
  const [images, setImages] = useState([]);

  useEffect(() => {
    fetch("https://dog.ceo/api/breeds/image/random/3")
      .then((r) => r.json())
      .then((data) => {
        // setting state in the useEffect callback
        setImages(data.message);
      });
  });

  return (
    <div>
      {images.map((image) => (
        <img src={image} key={image} />
      ))}
    </div>
  );
}

为了启动这个钩子,我们首先从React库中导入useEffect函数,然后调用它,同时传入一个回调函数。当组件渲染时,UseEffect将被调用,其副作用将基于传入的回调函数。UseEffect的一个常见用途是从API中获取数据,并在组件渲染时将其存储在一个状态中。

如上面的代码块所示,当组件加载时,会向狗的API发出一个获取请求,最终解析为一个响应对象,该对象被解析为JSON,最后通过调用setImages存储在图像状态中。这个状态然后被用于返回的JSX中,将被显示给用户。从用户的角度来看,个人在第一次加载网页时看到的只是一个显示的狗的图像。

然而,目前上面写useEffect的方式,最终会导致一个错误。原因是我们没有传入第二个参数,即依赖性数组。依赖数组允许我们控制useEffect何时被调用。在上面的例子中,由于我们没有传入一个依赖数组,useEffect将被连续调用,这将导致无休止的循环获取请求。这最终会导致API以达到速率限制为由将我们踢出去。

解决这个问题的方法是像这样传入一个空的依赖数组:

import React, { useEffect } from "react";

function DogPics() {
  const [images, setImages] = useState([]);

  useEffect(() => {
    fetch("https://dog.ceo/api/breeds/image/random/3")
      .then((r) => r.json())
      .then((data) => {
        // setting state in the useEffect callback
        setImages(data.message);
      });
  }, [] ); // added empty dependency array

  return (
    <div>
      {images.map((image) => (
        <img src={image} key={image} />
      ))}
    </div>
  );
}

通过包括一个空的依赖关系数组作为useEffect的第二个参数,useEffect将只在组件第一次安装时被调用。这将防止无休止的获取请求的循环,并且只在组件第一次加载时获取一次数据。

另一种控制useEffect何时被调用的方法是像这样将一个状态传入依赖数组:

import React, { useEffect } from "react";

function DogPics() {
  const [images, setImages] = useState([]);

  useEffect(() => {
    fetch("https://dog.ceo/api/breeds/image/random/3")
      .then((r) => r.json())
      .then((data) => {
        // setting state in the useEffect callback
        setImages(data.message);
      });
  }, [images] ); // added images state dependency array

  return (
    <div>
      {images.map((image) => (
        <img src={image} key={image} />
      ))}
    </div>
  );
}
Note: Although adding the images state in the dependency array in this context does not logically make sense, this is purely for demonstration purposes.

使用我们一直使用的同样的代码块,我们现在把图像状态传入依赖数组。所以现在useEffect将在组件第一次安装时被调用,随后如果依赖数组中的状态更新,它将被再次调用。所以在我们的例子中,当组件第一次挂载时调用useEffect后,如果图像状态被更新,它将被再次调用。

结论

当网站第一次加载时,从API中获取数据并将其存储在某种类型的变量中,这是所有新开发者都应该熟悉的基本概念。状态和效果钩子都有助于简化这个过程,这显示了React钩子的有效性和效率。作为开发者,我们会遇到许多其他的钩子,这些钩子会帮助我们进行React开发,但在涉及到React钩子时,应该牢记两个一般规则:

  1. 只在顶层调用Hooks。
  2. 只从React函数组件中调用Hooks。

关于钩子或React的更多信息,你可以随时参考他们网站上的文档。

祝您好运!