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钩子时,应该牢记两个一般规则:
- 只在顶层调用Hooks。
- 只从React函数组件中调用Hooks。
关于钩子或React的更多信息,你可以随时参考他们网站上的文档。
祝您好运!