網(wǎng)站首頁 編程語言 正文
hooks是什么
hooks理解字面意思就是鉤子,是一些可以讓你在函數(shù)組件里鉤入 React state以及生命周期等特性的函數(shù),可以讓不編寫class的情況下使用state以及其他的React特性
Hooks的作用
為函數(shù)組件提供狀態(tài),生命周期等原本在class組件中才提供的功能
Hooks只能在函數(shù)組件中使用
可以理解為通過Hooks為函數(shù)組件鉤入class組件的特性
使用Hooks組件前后開發(fā)模式的對比
使用前(React v 16.8前):class組件(提供狀態(tài))+函數(shù)組件(展示內(nèi)容)
使用后(React v 16.8后):Hooks(提供狀態(tài))+函數(shù)組件(展示內(nèi)容)
Hooks使用策略
(1)react沒有計劃從React中移除class
(2)hook和現(xiàn)有代碼可以同時工作,可以漸進式使用
不推薦直接使用Hooks大規(guī)模重構(gòu)現(xiàn)有組件
推薦新功能使用Hooks,復(fù)雜功能實現(xiàn)不來,也可以繼續(xù)使用class
(3)class組件相關(guān)的API在hooks里面可以不用
state setState 鉤子函數(shù),this相關(guān)用法
(4)原來學(xué)習(xí)的內(nèi)容還是要用
JSX:{} onClick={} 、條件渲染、列表渲染、樣式處理
組件:函數(shù)組件,組件通訊
react開發(fā)理念:單向數(shù)據(jù)流,狀態(tài)提升
為什么要有Hooks
首先我們要了解react的本質(zhì),接著從函數(shù)組件和類組件進行分析優(yōu)缺點
react本質(zhì):用于構(gòu)建用戶界面的javascript庫,是對特定功能的封裝,主要對url進行拆分
react組件的模型其實很直觀,就是從model到view的映射,這里的model對應(yīng)的是react的state和props
函數(shù)式組件的好處:
- 函數(shù)本身比較簡單,更好的勝任根據(jù)狀態(tài)來渲染url這件事
- hooks讓函數(shù)組件內(nèi)部有了維護狀態(tài)的能力
- hooks帶來了組件的邏輯復(fù)用的能力
class組件自身的問題:
- 在根據(jù)狀態(tài)來渲染url這件事上,class組件并沒有發(fā)揮它的重要功能
- 組件之間很少繼承
- 組件之間很少相互訪問
useState
作用:為函數(shù)組件提供state狀態(tài)
步驟:
- 導(dǎo)入useState函數(shù)
- 調(diào)用useState函數(shù),傳入初始值,返回狀態(tài)和修改狀態(tài)的函數(shù)
- 使用:在jsx中展示狀態(tài),特定的時機調(diào)用修改狀態(tài)的函數(shù)修改狀態(tài)
- 定義state數(shù)據(jù),返回一個數(shù)組,有兩個值,第一個值,定義數(shù)據(jù)初始化的值,第二個值,修改數(shù)據(jù)函數(shù),可以做到頁面的響應(yīng)式
useState兩種格式:
格式1:傳入值 useState(0) 或useState('abc')
格式2:傳入回調(diào),useState({上一次的值}=>{return 新值})
- 回調(diào)函數(shù)的返回值就是狀態(tài)的當(dāng)前值
- 回調(diào)函數(shù)只會觸發(fā)一次
代碼展示
import React, { useState } from 'react'
export default function UseState() {
let [count,setCount]=useState(10)
// 他是異步的操作,在頁面數(shù)據(jù)會進行更新,但是下面打印的數(shù)據(jù)是沒有更新,原因是因為他是異步的
const plus=()=>{
setCount(count+5)
}
return (
<div>
{/* 函數(shù)組件中沒有this指向,我們可以直接調(diào)用 */}
<div>{count}</div>
<button onClick={()=>setCount(count++)}>加加</button>
<button onClick={plus}>plus</button>
</div>
)
}
注意:上面必須引入useState 使用
useEffect使用
函數(shù)式組件:
主作用:就是根據(jù)數(shù)據(jù)(state/props)渲染ul
副作用:數(shù)據(jù)請求,手動修改DOM、開啟定時器、清空定時器、localStorage操作等
副作用:只要是渲染數(shù)據(jù)之外的操作都是副作用,副作用不一定非要寫在useEffect里,可以寫外面,但是寫useEffect會起到約束作用
執(zhí)行時機(以下兩種情況會執(zhí)行Effect):
- 組件掛載時,執(zhí)行一次(相當(dāng)于生命周期中componentDidMount)
- 組件更新時,可能執(zhí)行多次(相當(dāng)于生命周期中的componentDidUpdate)
在實際開發(fā)中,副作用是不可避免的,react專門用useEffect來處理組件中的副作用
useEffect依賴項
有兩個參數(shù):(參數(shù)一:(副作用函數(shù)),參數(shù)二:(執(zhí)行副作用函數(shù)的依賴項,他決定了什么時候執(zhí)行參數(shù)1(副作用)))
- 如果不設(shè)置第二個參數(shù),那么每次頁面更新他都會執(zhí)行
- 參數(shù)是空數(shù)組,永遠(yuǎn)只執(zhí)行第一次
- 指定依賴項,執(zhí)行時機(初始化執(zhí)行一次,依賴項發(fā)生變化執(zhí)行一次)可以有多個依賴項
- useEffect() 代替三個生命周期函數(shù) componentDidMount compoentDidUpdate 鉤子函數(shù), componentWillUnmount 生命周期
使用情景
- 事件綁定
- 發(fā)送請求獲取數(shù)據(jù)等 axios ajax
useEffect(()=>{ 邏輯}) 頁面數(shù)據(jù)只要更新就會觸發(fā)useEffect()
useEffect(()=>{},[]) useEffect() 只執(zhí)行一次,只有頁面第一次加載的時候觸發(fā),componentDidMount
useEffect(()=>{}, [num,count]) 監(jiān)聽數(shù)據(jù)改變執(zhí)行,num和count發(fā)生變化的時候觸發(fā)。compoentDidUpdate
useEffect(()=>{
return ()=>{
console.log("相當(dāng)于compoentDidUnmount")
}
},[])
//回調(diào)函數(shù)返回函數(shù),返回的函數(shù)相當(dāng)于銷毀生命周期函數(shù)。
useMemo使用
相當(dāng)于vue中計算屬性,他一般需要返回一個結(jié)果,具有緩存性的效果
useMemo他是在DOM更新的時候觸發(fā)的,useEffect() DOM更新后觸發(fā)的副作用函數(shù)
緩存復(fù)雜運算的結(jié)果,避免重復(fù)調(diào)用執(zhí)行
useMemo頁面一般會渲染第一次執(zhí)行后的結(jié)果
代碼展示
import React, { useMemo, useState } from 'react'
export default function UseState() {
let [count,setCount]=useState(10)
// useMemo必須有返回值,而且他是在dom更新發(fā)生變化,比useEffect執(zhí)行的快,useEffect是dom更新完才執(zhí)行的,監(jiān)聽count值變化
const double=useMemo(()=>{
console.log('useMemo觸發(fā)');
return count+6
},[count])
return (
<div>
{/* 函數(shù)組件中沒有this指向,我們可以直接調(diào)用 */}
<div>{count} {double}</div>
<button onClick={()=>setCount(count*2)}>count二倍</button>
</div>
)
}
useMemo緩存組件方式
第一種通過useMemo緩存組件
//useMemoe緩存組件
function Home() {
let [count,setcount] = useState(10)
let [num,setnum] = useState(20)
//通過useMemoe對組件進行緩存,避免父組件中根子組件無關(guān)數(shù)據(jù)更新導(dǎo)致子組件的重新渲染。
let theme = useMemo(()=>{
return (
<Theme count={count}></Theme>
)
},[count])
return (
<div>
<h3 >count--{count}</h3>
<button onClick={()=>setcount(count+1)}>count++</button>
<h3 >num--{num}</h3>
<button onClick={()=>setnum(num+1)}>num++</button>
<hr />
{theme}
</div>
)
}
function Theme(props){
useEffect(()=>{
console.log("子組件渲染")
});
return (
<h3>子組件接受數(shù)據(jù){props.count}</h3>
)
}
第二種通過react自帶的memo方法
memo是一個高階組件方法,接受一個組件作為參數(shù),根據(jù)組件傳遞的參數(shù)值,對組件進行緩存,避免組件的多余的DOM渲染效果
function Home() {
let [count,setcount] = useState(10)
let [num,setnum] = useState(20)
return (
<div>
<h3 >count--{count}</h3>
<button onClick={()=>setcount(count+1)}>count++</button>
<h3 >num--{num}</h3>
<button onClick={()=>setnum(num+1)}>num++</button>
<hr />
<Theme count={count}></Theme>
</div>
)
}
//通過memo對組件進行緩存,避免父組件中根子組件無關(guān)數(shù)據(jù)更新導(dǎo)致子組件的重新渲染。
const Theme = memo((props)=>{
useEffect(()=>{
console.log("子組件渲染")
});
return (
<h3>子組件接受數(shù)據(jù){props.count}</h3>
)
})
useMemo和useEffect的區(qū)別
不同點:
useEffect是在dom更新后觸發(fā)的副作用函數(shù),他被稱為副作用函數(shù)就是因為他在我們更新完成之后才通知我們,類似于馬后炮,useEffect不需要返回值,他沒有數(shù)據(jù)緩存的作用
useMemo是在dom更新時觸發(fā)的,useMemo必須要返回數(shù)據(jù)的結(jié)果,他是具有緩存數(shù)據(jù)的作用
共同點:
如果非要說共同點,那么他倆都有兩個參數(shù),并且第二個參數(shù)如果是空[]的話,那么他的數(shù)據(jù)只會執(zhí)行一次,也可以給他設(shè)置監(jiān)聽項,[監(jiān)聽值的名稱],第二個參數(shù)是可選參數(shù),也可以不寫,不寫就是頁面只要發(fā)生一點改變,就會重新渲染一次,浪費數(shù)據(jù)更新的性能
useCallback使用
在上述的例子中如果我們傳遞的是普通的變量,緩存后,父組件更新的話不會導(dǎo)致子組件的更新,但是如果你傳遞的是一個函數(shù),父組件的每次更新都會重新調(diào)用一次函數(shù),這個時候就會不同函數(shù)調(diào)用,會導(dǎo)致子組件的重新渲染,如果我們還要做組件緩存,我們可以使用useCallback() , 可以對函數(shù)進行一個緩存的作用
代碼展示
function Home() {
let [count,setcount] = useState(10)
let [num,setnum] = useState(20)
const handlerCount = ()=>{
console.log(count);
}
const callback = useCallback(()=>{
handlerCount();
},[count]);
return (
<div>
<h3 >count--{count}</h3>
<button onClick={()=>setcount(count+1)}>count++</button>
<h3 >num--{num}</h3>
<button onClick={()=>setnum(num+1)}>num++</button>
<hr />
<Theme count={count} handle={callback}></Theme>
</div>
)
}
//通過memo對組件進行緩存,避免父組件中根子組件無關(guān)數(shù)據(jù)更新導(dǎo)致子組件的重新渲染。
const Theme = memo((props)=>{
useEffect(()=>{
console.log("子組件渲染")
});
return (
<div>
<h3>子組件接受數(shù)據(jù){props.count}</h3>
<button onClick={()=>props.handle()}>點擊</button>
</div>
)
})
useMemo,memo,useCallback如何提升性能的(面試題必問)?
useMemo主要的作用是緩存復(fù)雜運算的數(shù)據(jù)返回的結(jié)果,有兩個參數(shù),第二個參數(shù)可以定義要監(jiān)聽的數(shù)據(jù),并且需要返回,跟useEffect第二個參數(shù)的作用類同
當(dāng)父組件的組件更新的時候會導(dǎo)致子組件的重新渲染,但是如果父組件的更新的數(shù)據(jù)沒有傳遞給子組件的話,這時候還讓子組件重新渲染的話,會導(dǎo)致組件更新性能消耗比較大
所以說這個時候我們可以使用useMemo,或者使用react內(nèi)置的memo方法對子組件進行緩存,這樣只有父組件更新跟子組件有關(guān)的數(shù)據(jù)時才會導(dǎo)致子組件重新渲染,從而提高組件的渲染性能
但是如果我們給子組件傳遞的是一個方法的時候,上面的useMemo,memo方法緩存就不起作用了,原因是父組件每更新一次會導(dǎo)致方法的重新調(diào)用,進而導(dǎo)致子組件的重新更新,這時候我們可以用到useCallback對傳遞的方法進行緩存,監(jiān)聽數(shù)據(jù)更新后才會重新調(diào)用方法,從而提高組件的渲染性能
useContext使用
用來獲取context狀態(tài)樹的內(nèi)容數(shù)據(jù)的Hooks的APi,相當(dāng)于class組件中static contextType = react.createContext創(chuàng)建的對象內(nèi)容
代碼展示
import React, { useContext, useState } from 'react';
//useContext用于獲取context狀態(tài)樹的值
// 首先創(chuàng)建一個空的context對象
const ThemContext =React.createContext();
function UseState() {
let [color,setColor]=useState('#ff0000')
return (
<div>
{/* 通過Provider傳過來一個value值,是一個對象 */}
<ThemContext.Provider value={{color:color}}>
<button onClick={()=>setColor('pink')}>粉色</button>
<button onClick={()=>setColor('blue')}>藍(lán)色</button>
<button onClick={()=>setColor('green')}>綠色</button>
<Son></Son>
</ThemContext.Provider>
</div>
)
}
// 子組件
function Son(props) {
// 通過useContext獲取父組件傳過來的值
const context=useContext(ThemContext)
return (
<div>
{/* 然后對他進行樣式綁定 */}
<h3 style={context}>hello,react</h3>
</div>
)
}
export default UseState
useRef使用
useRef 作用相當(dāng)于class組件React.createRef()的作用,用于創(chuàng)建ref節(jié)點對象的內(nèi)容
//創(chuàng)建一個ref對象的內(nèi)容
let inp = useRef(null);
const setVal =()=>{
console.log(inp.current.value);
}
<input placeholder='輸入內(nèi)容' ref={inp} onChange={setVal}/>
為什么在函數(shù)組件中無法使用ref
普通的類組件有實例所以可以用React。createRef()掛載到節(jié)點或者組件上,然后通過this獲取到該節(jié)點或組件,正常情況下ref是不能掛到函數(shù)組件上,因為函數(shù)組件沒有實例
如何在類組件中使用ref屬性
我們可以通過forwardRef將ref父類的ref作為參數(shù)傳入函數(shù)式組件中
forwardRef是一個高階函數(shù),跟memo一樣
還有一種方法就是把函數(shù)組件改成類組件
function Home() {
//定義一個初始化變量
let inpRef = useRef(null);
const getTheme = ()=>{
console.log(inpRef);
}
return (
<div>
<input placeholder='輸入內(nèi)容'/>
<button onClick={getTheme}>獲取子組件對象</button>
<hr />
<Theme ref={inpRef}/>
</div>
)
}
const Theme = forwardRef(function(props,ref){
return (
<h3 ref={ref}>文字內(nèi)容顯示</h3>
)
})
自定義hooks
寫一個自定義頁面標(biāo)題的效果,路由中使用
import { useEffect } from "react";
//自定義顯示標(biāo)題的Hooks的方法內(nèi)容
const useTitle = (title) => {
useEffect(() => {
document.title = title;
return ()=>{
document.title="React 頁面"
}
}, []);
return;
}
export { useTitle };
import { useTitle } from "../context/hooksApi"
export default function My(){
useTitle("個人中心")
return (
<div>
<h3>個人中心</h3>
</div>
)
}
還有其他的自定義hooks API方法,這舉例的是一種
原文鏈接:https://blog.csdn.net/qq_60976312/article/details/125624109
相關(guān)推薦
- 2022-03-22 C++using聲明和using編譯指令_C 語言
- 2022-08-18 Python如何獲取實時股票信息的方法示例_python
- 2022-06-30 Python利用shutil模塊實現(xiàn)文件夾的復(fù)制刪除與裁剪_python
- 2023-12-10 該方法僅能傳入 lambda 表達(dá)式產(chǎn)生的合成類
- 2023-02-12 Golang中反射的常見用法分享_Golang
- 2022-06-19 C++簡明講解類型轉(zhuǎn)換的使用與作用_C 語言
- 2023-01-10 利用C#實現(xiàn)修改圖片透明度功能_C#教程
- 2023-07-31 elementui中el-tabs切換實時更新數(shù)據(jù)
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支