React Hooks教程--useState、useEffect以及如何创建自定义钩子
钩子是在React 16.8中首次引入的。它们非常棒,因为它们可以让你使用更多的React功能--比如管理你的组件的状态,或者在状态发生某些变化时执行后置效果,而不需要写一个类。
在这篇文章中,你将学习如何在React中使用Hooks,以及如何创建你自己的自定义Hooks。请记住,你可以只对功能组件使用钩子。
什么是useState Hook?
你的应用程序的状态一定会在某个时刻发生变化。这可能是一个变量的值,一个对象,或者你的组件中存在的任何类型的数据。
为了使这些变化能够反映在DOM中,我们必须使用一个叫做useState
的React钩子。它看起来像这样。
import { useState } from "react"; function App() { const [name, setName] = useState("Ihechikara"); const changeName = () => { setName("Chikara"); }; return ( <div> <p>My name is {name}</p> <button onClick={changeName}> Click me </button> </div> ); } export default App; 复制代码
让我们再仔细看一下上面的代码是怎么回事。
import { useState } from "react"; 复制代码
为了能够使用这个钩子,你必须从React中导入 useState
钩子。我们正在使用一个名为app
的功能组件。
const [name, setName] = useState("Ihechikara"); 复制代码
之后,你必须创建你的状态,并给它一个初始值(或初始状态),它是 "Ihechikara"。这个状态变量被称为name
,而setName
是用于更新其值的函数。
对ES6的一些特性有一个很好的理解将有助于你掌握React的基本功能。上面,我们用destructuring赋值为useState("Ihechikara")
中的状态分配了一个初始名称值。
return ( <div> <p>My name is {name}</p> <button onClick={changeName}> Click me </button> </div> ); } 复制代码
接下来,DOM有一个包含名字变量的段落和一个按钮,点击后会触发一个函数。changeName()
函数调用setName()
函数,然后将名称变量的值改为传递给setName()
函数的值。
你的状态值不能是硬编码的。在下一节,你将看到如何在表单中使用useState
钩子。
对于React的初学者来说,请注意你在返回语句之前创建你的函数和变量。
如何在表单中使用useState钩子
本节将帮助你了解如何为你的表单创建状态值,并在需要的时候更新它们。这个过程与我们在上一节中看到的并无太大区别。
像往常一样,导入useState
钩子。
import { useState } from "react"; 复制代码
我们将像之前那样创建初始状态。但在这种情况下,它将是一个空字符串,因为我们要处理的是一个输入元素的值。硬编码值意味着每当页面被重新加载时,输入元素就会有这个值。就是说。
const [name, setName] = useState(""); 复制代码
现在我们已经创建了状态,让我们在DOM中创建输入元素,并将name变量分配为它的初始值。它看起来像这样。
return ( <div> <form> <input type="text" value={name} onChange={(e) => setName(e.target.value)} placeholder="Your Name" /> <p>{name}</p> </form> </div> ); 复制代码
你会注意到,我们没有在返回语句上方创建一个函数来更新状态的值--但如果你决定使用这种方法,还是可以的。
在这里,我们使用onChange
事件监听器,它等待着输入字段中任何数值的变化。每当有变化时,一个匿名函数(以事件对象为参数)被触发,它反过来调用setName()
函数,用输入字段的当前值更新名称变量。
下面是最终代码的样子。
import { useState } from "react"; function App() { const [name, setName] = useState(""); return ( <div> <form> <input type="text" value={name} onChange={(e) => setName(e.target.value)} placeholder="Your Name" /> <p>{name}</p> </form> </div> ); } export default App; 复制代码
什么是useEffect Hook?
效果钩子,就像它的名字所暗示的那样,在每次有状态变化时执行一个效果。默认情况下,它在第一次渲染后和每次状态更新时运行。
在下面的例子中,我们创建了一个状态变量count
,初始值为0。每次点击DOM中的一个按钮,这个变量的值就会增加1。useEffect钩子将在每次count
变量变化时运行,然后向控制台记录一些信息。
import { useState, useEffect } from "react"; function App() { const [count, setCount] = useState(0); useEffect(() => { console.log(`You have clicked the button ${count} times`) }); return ( <div> <button onClick={() => setCount(count + 1)}>Click me</button> </div> ); } export default App; 复制代码
如果你要 "钩住 "这个React功能,你导入所需钩子的第一行代码总是很重要。我们导入了上面使用的两个钩子。
import React, { useState, useEffect } from "react"; 复制代码
注意,你可以使用useEffect钩子来实现各种效果,比如从外部API获取数据(你会在本文的另一节看到),改变组件中的DOM,等等。
useEffect的依赖性
但是如果你想让你的效果只在第一次渲染后运行,或者你有多个状态,而只想在其中一个状态下附加一个后置效果,该怎么办?
我们可以通过使用一个依赖数组来做到这一点,该数组在useEffect
钩子中作为第二个参数传入。
如何运行一次效果
对于第一个例子,我们将传入一个数组,让useEffect钩子只运行一次。下面是一个关于如何工作的例子。
import { useState, useEffect } from "react"; function App() { const [count, setCount] = useState(0); useEffect(() => { console.log(`You have clicked the button ${count} times`) }, []); return ( <div> <button onClick={() => setCount(count + 1)}>Click me</button> </div> ); } export default App; 复制代码
上面的代码与上一节相同,只是useEffect钩子接受一个空数组[]
作为第二个参数。当我们让数组为空时,效果将只运行一次,而不考虑它所连接的状态的变化。
如何将一个效果附加到一个特定的状态
import { useState, useEffect } from "react"; function App() { const [count, setCount] = useState(0); useEffect(() => { console.log(`You have clicked the first button ${count} times`); }, [count]); const [count2, setCount2] = useState(0); useEffect(() => { console.log(`You have clicked the second button ${count2} times`) }, [count2]); return ( <div> <button onClick={() => setCount(count + 1)}>Click me</button> <button onClick={() => setCount2(count2 + 1)}>Click me</button> </div> ); } export default App; 复制代码
在上面的代码中,我们创建了两个状态和两个useEffect钩子。每个状态都有一个后置效果,通过将状态的名称[count]
和[count2]
传递给相应的useEffect数组依赖。
因此,当count
的状态发生变化时,负责观察这些变化的useEffect钩子将执行分配给它的任何后效应。这也适用于count2
。
如何创建你自己的钩子
现在你已经看到了React中的一些内置钩子(查看文档以查看更多的钩子),现在是时候创建我们自己的自定义钩子了。
你的钩子能做什么有很多可能性。在本节中,我们将创建一个钩子,从外部API获取数据,并将数据输出到DOM中。这可以节省你在不同的组件中重复创建相同逻辑的压力。
第1步 - 创建你的文件
当为自定义钩子创建一个新的文件时,一定要确保文件的名字以 "use "开头。我将我的文件称为useFetchData.js
。
第2步 - 创建钩子的功能
如前所述,我们将使用这个钩子从外部API获取数据。它将是动态的,所以没有什么需要硬编码的。下面是我们要做的。
import { useState, useEffect} from 'react' function useFetchData(url) { const [data, setData] = useState(null); useEffect(() => { fetch(url) .then((res) => res.json()) .then((data) => setData(data)) .catch((err) => console.log(`Error: ${err}`)); }, [url]); return { data }; } export default useFetchData 复制代码
为了解释上面发生的事情。
我们导入钩子:
import { useState, useEffect} from 'react'
。我们创建一个状态来保存将被返回的数据--初始状态将是空的:
const [data, setData] = useState(null);
。返回的数据将使用setData()
函数更新data
变量的值。我们创建一个效果,在第一次渲染和每次
url
参数变化时运行。
useEffect(() => { fetch(url) .then((res) => res.json()) .then((data) => setData(data)) .catch((err) => console.log(`Error: ${err}`)); }, [url]); 复制代码
我们返回数据变量。
return { data };
第3步 - 创建一个新文件并导入自定义钩子
所以我们已经创建了我们的自定义钩子。现在让我们创建一个新的组件,看看我们如何在其中使用useFetchData
钩子。
import useFetchData from './useFetchData' function Users() { const { data } = useFetchData("https://api.github.com/users"); return ( <div> {data && ( data.map((user) =>( <div className="text-white" key={user.id}> <h1> {user.login} </h1> <p> { user.type } </p> </div> )) )} </div> ) } export default Users; 复制代码
让我们把它分解一下。
我们将该组件命名为
Users.js
,因为它将用于从GitHub的API(可以是任何API)获取用户数据。我们导入了一个自定义钩子:
import useFetchData from './useFetchData'
。我们在返回语句前引用了这个钩子,并传入了URL。
const { data } = useFetchData("https://api.github.com/users");
。一个API请求将被发送到你传入的任何URL。使用
&&
操作符,只有当数据变量被来自API请求的数据更新时,DOM才会被更新,也就是说,当data != null
。我们对返回的数据进行循环,并将其输出到DOM中。
总结
如果你已经跟进到这一点,那么你应该对React中的钩子有一个很好的理解,如何使用它们,以及如何创建你自己的自定义钩子。而完全理解这些的最好方法是实践,所以不要只是通读。
这篇文章涵盖了钩子的核心领域,但它不会教你关于钩子的所有知识。所以请确保你查看React JS文档,以便你能了解更多关于它们的信息。
作者:迪鲁宾
链接:https://juejin.cn/post/7023213712789995550