React 18 Hooks:函数组件的强大工具
🤍 前端开发工程师、技术日更博主、已过CET6
🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1
🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》
🍚 蓝桥云课签约作者、上架课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入门到实战全面掌握 uni-app》
💬 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。
文章目录
- 一、背景与用途
- 二、常用Hooks
- (一)`useState`
- (二)`useEffect`
- (三)`useContext`
- (四)`useRef`
- 三、自定义Hooks
一、背景与用途
在React 18中,Hooks是一种在函数组件中使用React特性的方式,它可以让你在不编写类组件的情况下使用状态(state)和其他React特性。Hooks的出现主要是为了解决函数组件之前无法拥有自身状态和生命周期方法的问题,使得函数组件在功能上更加强大,代码更加简洁和易于理解。
二、常用Hooks
(一)useState
- 基本概念与用法
useState
是一个Hook,用于在函数组件中添加状态。它接收一个初始值作为参数,并返回一个包含两个元素的数组。第一个元素是当前状态的值,第二个元素是一个用于更新状态的函数。- 例如,创建一个简单的计数器组件:
import React, { useState } from 'react'; const Counter = () => { const [count, setCount] = useState(0); const increment = () => { setCount(count + 1); }; return ( <div> <p>Count: {count}</p> <button onClick={increment}>Increment</button> </div> ); };
- 在这个例子中,
useState(0)
初始化了一个状态count
,初始值为0。setCount
是用于更新count
状态的函数,当用户点击按钮时,increment
函数被调用,通过setCount(count + 1)
更新count
的值,组件会重新渲染以显示新的计数。
- 更新状态的注意事项
- 不可变数据原则:在更新状态时,要遵循不可变数据原则。例如,如果状态是一个对象或数组,不要直接修改它,而是要返回一个新的对象或数组。错误的做法是:
const [state, setState] = useState({ value: 0 }); const wrongUpdate = () => { state.value++; // 错误,直接修改状态 setState(state); };
- 正确的做法可以是使用对象展开运算符来返回一个新的对象:
const [state, setState] = useState({ value: 0 }); const correctUpdate = () => { setState((prevState) => ({ ...prevState, value: prevState.value + 1 })); };
(二)useEffect
- 基本概念与用法
useEffect
用于在函数组件中执行副作用操作,例如数据获取、订阅事件、手动修改DOM等。它接收一个函数作为主要参数,这个函数会在组件渲染到屏幕之后执行。- 例如,在组件挂载时获取数据:
import React, { useState, useEffect } from 'react'; const DataFetchingComponent = () => { const [data, setData] = useState(null); useEffect(() => { const fetchData = async () => { const response = await fetch('https://api.example.com/data'); const jsonData = await response.json(); setData(jsonData); }; fetchData(); }, []); return ( <div> {data? ( <div> <p>{data}</p> </div> ) : ( <p>Loading...</p> )} </div> ); };
- 在这个例子中,
useEffect
中的函数在组件挂载时(因为依赖项数组[]
为空,表示只在挂载时执行)调用fetchData
函数来获取数据。获取到数据后,通过setData
更新组件状态,组件会重新渲染以显示数据。如果fetchData
函数是一个异步函数,需要在useEffect
内部定义并调用,以确保正确的异步执行顺序。
- 依赖项数组的作用与使用
- 依赖项数组用于控制
useEffect
函数的执行时机。如果依赖项数组中的值发生变化,useEffect
中的函数会再次执行。 - 例如,根据一个输入值来获取相关数据:
import React, { useState, useEffect } from 'react'; const InputDataFetchingComponent = () => { const [inputValue, setInputValue] = useState(''); const [data, setData] = useState(null); useEffect(() => { const fetchData = async () => { const response = await fetch(`https://api.example.com/data?input=${inputValue}`); const jsonData = await response.json(); setData(jsonData); }; fetchData(); }, [inputValue]); const handleInputChange = (e) => { setInputValue(e.target.value); }; return ( <div> <input type="text" value={inputValue} onChange={handleInputChange} /> {data? ( <div> <p>{data}</p> </div> ) : ( <p>Loading...</p> )} </div> ); };
- 在这里,
useEffect
的依赖项数组包含inputValue
。当inputValue
发生变化时,useEffect
中的fetchData
函数会再次执行,获取新的数据并更新组件状态。
- 依赖项数组用于控制
(三)useContext
- 基本概念与用法
useContext
用于在函数组件中访问由Context.Provider
提供的上下文(context)值。它接收一个Context
对象作为参数,并返回该上下文对象的当前值。- 例如,创建一个主题上下文并在组件中使用:
- 首先,创建主题上下文:
import React from 'react'; const ThemeContext = React.createContext('light');
- 然后,在顶层组件中提供主题值:
const App = () => { const [theme, setTheme] = useState('light'); return ( <ThemeContext.Provider value={theme}> <Header /> <MainContent /> <Footer /> </ThemeContext.Provider> ); };
- 最后,在需要使用主题值的组件中通过
useContext
获取主题:
const Button = () => { const theme = React.useContext(ThemeContext); return ( <button className={`button - ${theme}`}>点击我</button> ); };
- 在这个例子中,
useContext(ThemeContext)
在Button
组件中获取了由App
组件中ThemeContext.Provider
提供的主题值,然后可以根据这个主题值来设置按钮的样式。
(四)useRef
- 基本概念与用法
useRef
返回一个可变的ref
对象,其current
属性被初始化为传入的初始值。ref
对象在组件的整个生命周期内保持不变,可以用于存储和访问DOM元素或任何可变的值,并且这个值在组件重新渲染时不会丢失。- 例如,访问和操作DOM元素:
import React, { useRef } from 'react'; const InputFocusComponent = () => { const inputRef = useRef(null); const handleClick = () => { inputRef.current.focus(); }; return ( <div> <input ref={inputRef} type="text" /> <button onClick={handleClick}>聚焦输入框</button> </div> ); };
- 在这个例子中,
useRef(null)
创建了一个ref
对象inputRef
,并通过input
元素的ref
属性将其与输入框关联。当按钮被点击时,handleClick
函数通过inputRef.current.focus()
访问输入框元素并使其获得焦点。
- 与
useState
的区别useState
用于管理组件状态,当状态更新时会触发组件重新渲染;而useRef
主要用于存储一个持久的引用,其current
属性的变化不会触发组件重新渲染。- 例如,比较一个使用
useState
和useRef
的计数器组件: - 使用
useState
:
import React, { useState } from 'react'; const CounterWithState = () => { const [count, setCount] = useState(0); const handleClick = () => { setCount(count + 1); }; return ( <div> <p>Count: {count}</p> <button onClick={handleClick}>Increment</button> </div> ); };
- 使用
useRef
:
import React, { useRef } from 'react'; const CounterWithRef = () => { const countRef = useRef(0); const handleClick = () => { countRef.current++; }; return ( <div> <p>Count: {countRef.current}</p> <button onClick={handleClick}>Increment</button> </div> ); };
- 在
CounterWithState
中,每次点击按钮,count
状态更新,组件会重新渲染;而在CounterWithRef
中,countRef.current
的值改变时,组件不会重新渲染。
三、自定义Hooks
- 定义与规则
- 自定义Hooks是一个以
use
开头的JavaScript函数,在函数内部可以使用其他React Hooks。自定义Hooks用于将组件中可复用的逻辑提取出来,使得代码更加模块化和易于维护。 - 例如,创建一个自定义的
useDebounce
Hook来实现防抖功能:
import React, { useState, useEffect } from 'react'; const useDebounce = (value, delay) => { const [debouncedValue, setDebouncedValue] = useState(value); useEffect(() => { const timer = setTimeout(() => { setDebouncedValue(value); }, delay); return () => clearTimeout(timer); }, [value, delay]); return debouncedValue; };
- 这个
useDebounce
Hook接收一个value
和一个delay
作为参数,返回经过防抖处理后的value
。在useEffect
中,通过定时器实现了防抖功能,当value
或delay
发生变化时,会重新设置定时器。
- 自定义Hooks是一个以
- 使用场景与示例
- 例如,在一个搜索框组件中使用
useDebounce
Hook来控制搜索请求的频率:
import React from 'react'; import useDebounce from './useDebounce'; const SearchBox = () => { const [searchTerm, setSearchTerm] = useState(''); const debouncedSearchTerm = useDebounce(searchTerm, 500); const handleSearch = () => { // 根据debouncedSearchTerm发送搜索请求,例如: console.log(`Searching for: ${debouncedSearchTerm}`); }; const handleInputChange = (e) => { setSearchTerm(e.target.value); }; return ( <div> <input type="text" value={searchTerm} onChange={handleInputChange} /> <button onClick={handleSearch}>Search</button> </div> ); };
- 在这个搜索框组件中,
useDebounce
Hook用于管理搜索词的状态。当用户在输入框中输入时,searchTerm
状态会更新,但只有在用户停止输入500
毫秒后,debouncedSearchTerm
才会更新,然后点击搜索按钮时,会根据debouncedSearchTerm
发送搜索请求,避免了频繁的搜索请求。
- 例如,在一个搜索框组件中使用