什么是React Hooks
React Hooks 是 React 16.8 新增的一種特性,它可以讓你在函數(shù)式組件中使用 state、生命周期、context 等 React 特性。Hooks 可以讓你將復(fù)雜的邏輯拆分成多個(gè)獨(dú)立可重用的函數(shù),并且使得這些函數(shù)更加易于理解和測(cè)試。
Class組件存在的問(wèn)題
-
復(fù)雜度高:類組件的定義和使用更加復(fù)雜繁瑣。在類組件中,需要繼承 React.Component 類,并且還要管理 this 指針、生命周期等,這使得代碼變得冗長(zhǎng)且難以理解。
-
嵌套層數(shù)過(guò)多:在傳統(tǒng) class 組件編寫方式中,為了實(shí)現(xiàn)一些復(fù)雜邏輯或者 UI 界面,在不同生命周期函數(shù)中進(jìn)行數(shù)據(jù)更新等操作容易導(dǎo)致代碼嵌套層數(shù)過(guò)多、閱讀性差,并且增加額外的復(fù)雜度和深度嵌套。
-
對(duì)功能模塊封裝比較困難:對(duì)于某個(gè)特定的功能模塊或業(yè)務(wù)邏輯而言,在類組件內(nèi)部如果想要將其封裝成一個(gè)獨(dú)立的方法或者函數(shù),則往往需要定義私有屬性或方法來(lái)實(shí)現(xiàn)封裝。然而這樣增加了代碼耦合性并降低了可重用性。
-
不利于優(yōu)化:由于 React 生命周期方法是按順序執(zhí)行的,因此在 componentDidMount 中做出昂貴計(jì)算可能會(huì)影響首次渲染時(shí)間。即使我們可以使用 shouldComponentUpdate 和 PureComponent 來(lái)減少重新渲染次數(shù), 但仍然無(wú)法避免當(dāng) props 和 state 變化時(shí)帶來(lái)的重新渲染。
React Hooks的優(yōu)勢(shì)?
React Hooks 的出現(xiàn)主要是為了解決 React Class組件的缺陷,并且讓我們的函數(shù)組件也可以擁有類似于類組件的狀態(tài)管理和副作用處理能力。
-
更簡(jiǎn)單的實(shí)現(xiàn)代碼復(fù)用:在React Hooks出現(xiàn)之前,我們想要實(shí)現(xiàn)代碼邏輯的復(fù)用需要使用到高階組件、render props 等技術(shù)來(lái)幫助我們完成,但這樣會(huì)增加額外的復(fù)雜度和深度嵌套,而 Hook 可以更輕松地實(shí)現(xiàn)代碼邏輯的重用。
-
使代碼邏輯更清晰:在傳統(tǒng)的 class 組件編寫方式中,在不同生命周期函數(shù)中進(jìn)行數(shù)據(jù)更新時(shí)容易導(dǎo)致代碼難以理解和維護(hù)。Hook 可以讓你將相關(guān)業(yè)務(wù)邏輯放到同一個(gè)函數(shù)內(nèi)部,從而提高可讀性并減少了模塊之間相互影響帶來(lái)風(fēng)險(xiǎn)。
-
更便于大規(guī)模開(kāi)發(fā)與測(cè)試:通過(guò)使用 Hook ,React 組件變成純粹聲明式渲染效果, 并且對(duì)應(yīng)該渲染結(jié)果只由 Props 和 State 決定, 這種特點(diǎn)使得 React 開(kāi)發(fā)者傾向于采取函數(shù)式編程(Functional Programming)范例去建立 UI.
-
更加靈活和自由 :Hooks 提供了很多新特性例如 state、useEffect、useContext 等,使得函數(shù)組件擁有了更多的功能和使用場(chǎng)景,并且可以自由地將這些 Hook 組合在一起以實(shí)現(xiàn)各種需求。
Hook的出現(xiàn),可以解決我們Class組件存在的這些問(wèn)題,它可以讓我們?cè)诓痪帉慶lass的情況下使用state以及其他的React特性。
注意:Hook只能在函數(shù)組件中使用,不能在類組件,或者函數(shù)組件之外的地方使用
Class組件和Functional組件對(duì)比
State Hook的API
useState
作用
useState
,它可以幫助我們?cè)诤瘮?shù)式組件中管理狀態(tài)。
語(yǔ)法
const [state, setState] = useState(initialState);
-
state
: 表示當(dāng)前的狀態(tài)值。 -
setState
: 是一個(gè)更新 state 值的函數(shù),調(diào)用該函數(shù)會(huì)重新渲染組件并更新?tīng)顟B(tài)。
參數(shù)
- initialState: 表示 state 的初始值??梢允侨魏蔚念愋停鐢?shù)字、字符串、數(shù)組或?qū)ο蟮取?/li>
返回值
- 數(shù)組:包含兩個(gè)元素 [state, setState]
使用方法
定義了一個(gè)計(jì)數(shù)器組件,使用了 useState
來(lái)初始化 count 狀態(tài),并且通過(guò) setCount 函數(shù)來(lái)更新 count 狀態(tài)。當(dāng)用戶點(diǎn)擊 Increment 按鈕時(shí),就會(huì)觸發(fā) increment 函數(shù)并將 count 增加一次。在此過(guò)程中,React 自動(dòng)檢測(cè)到狀態(tài)變化,并重新渲染頁(yè)面以顯示最新結(jié)果。
import React, { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
function increment() {
setCount(count + 1);
}
return (
<div>
<h1>Counter: {count}</h1>
<button onClick={increment}>Increment</button>
</div>
);
}
export default Counter;
Effect
作用
useEffect
它可以讓我們?cè)诤瘮?shù)式組件中執(zhí)行副作用操作(例如:從服務(wù)器獲取數(shù)據(jù)、手動(dòng)更新 DOM 等)。
語(yǔ)法
useEffect(effect, dependencies);
- effect:表示要執(zhí)行的副作用函數(shù)。
- dependencies:表示 useEffect 需要監(jiān)測(cè)變化的依賴項(xiàng)數(shù)組。
參數(shù)
- effect: 副作用函數(shù)。該函數(shù)會(huì)在每次渲染時(shí)都被調(diào)用,并且可以根據(jù)需要返回清理函數(shù)。如果不需要清理,則應(yīng)該返回 undefined 或者空函數(shù)。
- dependencies: 可選參數(shù),傳入一個(gè)數(shù)組來(lái)指定監(jiān)測(cè)哪些狀態(tài)/屬性變化而觸發(fā)副作用操作。
返回值
無(wú)返回值。
使用方法
import React, { useState, useEffect } from "react";
import axios from "axios";
function App() {
const [data, setData] = useState([]);
useEffect(() => {
async function fetchData() {
const result = await axios("https://jsonplaceholder.typicode.com/posts");
setData(result.data);
}
fetchData();
}, []);
return (
<div>
<h1>Posts</h1>
<ul>
{data.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
</div>
);
}
export default App;
在上面的代碼示例中我們定義了一個(gè)簡(jiǎn)單的應(yīng)用程序,我們使用了 useState
來(lái)初始化 data 狀態(tài),并且在 useEffect
中使用 axios 庫(kù)從服務(wù)器獲取數(shù)據(jù)。當(dāng)數(shù)據(jù)加載完成時(shí),我們使用 setData 函數(shù)更新 data 狀態(tài),并且通過(guò) map 方法將每個(gè)帖子的標(biāo)題顯示為列表項(xiàng)。在此過(guò)程中,React 自動(dòng)檢測(cè)到狀態(tài)變化,并重新渲染頁(yè)面以顯示最新結(jié)果。
useContext
作用
useContext
它可以讓我們?cè)诮M件樹(shù)中跨層級(jí)傳遞數(shù)據(jù),避免了繁瑣的 props 傳遞。
用法
首先,我們需要?jiǎng)?chuàng)建一個(gè) Context 對(duì)象來(lái)存儲(chǔ)要共享的數(shù)據(jù):
// MyContext.js
import React from "react";
const MyContext = React.createContext();
export default MyContext;
然后,在父組件中設(shè)置共享數(shù)據(jù),并將其作為 value
屬性傳遞給 Context.Provider 組件:
// App.js
import React, { useState } from "react";
import MyContext from "./MyContext";
import ChildComponent from "./ChildComponent";
function App() {
const [name, setName] = useState("John");
return (
<div>
<h1>Hello, {name}!</h1>
<MyContext.Provider value={name}>
<ChildComponent />
</MyContext.Provider>
</div>
);
}
export default App;
這里我們使用了 useState
來(lái)定義狀態(tài)變量 name
和用于更新該變量的函數(shù) setName
。然后將其作為值傳遞給 Context。
接下來(lái),在子組件中使用 useContext Hook 來(lái)獲取共享數(shù)據(jù)并進(jìn)行展示:
// ChildComponent.js
import React, { useContext } from "react";
import MyContexct from "./MyContexct";
function ChildComponent() {
const name = useContext(MyContexct);
return (
<div>
<h2>Child Component</h2>
<p>{name}, how are you doing?</p>
</div>
);
}
export default ChildComponent;
如上述代碼所示,我們可以通過(guò) useContext
Hook 來(lái)獲取 Context 中的共享數(shù)據(jù),并將其命名為 name
。然后在組件中展示該數(shù)據(jù)。
最終,當(dāng)我們運(yùn)行這個(gè)應(yīng)用程序時(shí),它將顯示一個(gè)包含 "Hello, John!"
和 "John, how are you doing?"
的頁(yè)面。
注意:到子組件無(wú)需通過(guò) props 獲取父組件的狀態(tài)變量值即可訪問(wèn)該值。
useReducer
作用
useReducer
它可以幫助我們使用 reducer 函數(shù)管理復(fù)雜的組件狀態(tài)。
用法
首先,我們需要定義一個(gè) reducer 函數(shù)來(lái)管理組件狀態(tài)。該函數(shù)接收兩個(gè)參數(shù):當(dāng)前狀態(tài)(state)和更新該狀態(tài)所需的操作(action)。然后根據(jù) action 的類型進(jìn)行相應(yīng)的處理并返回新的 state。
function reducer(state, action) {
switch (action.type) {
case "INCREMENT":
return { count: state.count + 1 };
case "DECREMENT":
return { count: state.count - 1 };
default:
throw new Error();
}
}
在上面的代碼中,我們創(chuàng)建了一個(gè)名為 reducer
的函數(shù),并根據(jù)傳入的不同類型執(zhí)行相應(yīng)操作來(lái)更新組件狀態(tài)。
接下來(lái),在父組件中使用 useReducer
Hook 來(lái)初始化和獲取共享數(shù)據(jù)以及 dispatch 方法:
import React, { useReducer } from "react";
import reducer from "./reducer";
function App() {
const [state, dispatch] = useReducer(reducer, { count: 0 });
function increment() {
dispatch({ type: "INCREMENT" });
}
function decrement() {
dispatch({ type: "DECREMENT" });
}
return (
<div>
<h2>Count:{state.count}</h2>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
</div>
);
}
export default App;
如上述代碼所示,通過(guò)調(diào)用 useReducer
Hook,我們可以獲取到當(dāng)前的狀態(tài)(state)和 dispatch 方法。其中第一個(gè)參數(shù)是 reducer 函數(shù),第二個(gè)參數(shù)是初始狀態(tài)值。在這里我們使用了 { count: 0 }
作為初始 state 值。
然后在父組件中定義兩個(gè)函數(shù):increment 和 decrement,它們分別調(diào)用 dispatch({ type: "INCREMENT" })
和 dispatch({ type: "DECREMENT" })
來(lái)更新共享數(shù)據(jù)。
最終,在返回的 JSX 中展示當(dāng)前計(jì)數(shù)器的值并添加增加/減少按鈕來(lái)觸發(fā)對(duì)應(yīng)操作即可。
useCallback
作用
useCallback
它可以幫助我們優(yōu)化性能并避免不必要的重新渲染。
用法
首先,我們需要理解什么是函數(shù)記憶。在 JavaScript 中,如果兩個(gè)相同參數(shù)值之間存在對(duì)應(yīng)關(guān)系,則稱這些函數(shù)有“記憶”。因此,在進(jìn)行計(jì)算時(shí)使用已經(jīng)計(jì)算過(guò)的結(jié)果而不是再次運(yùn)行該函數(shù)以提高效率。
接下來(lái),請(qǐng)看如下代碼示例:
import React, { useState } from "react";
function App() {
const [count, setCount] = useState(0);
function handleClick() {
console.log("Clicked!");
setCount(count + 1);
}
return (
<div>
<h2>Count: {count}</h2>
<button onClick={handleClick}>Increment</button>
</div>
);
}
export default App;
上面的代碼中展示了一個(gè)簡(jiǎn)單的計(jì)數(shù)器組件,并且定義了一個(gè)名為 handleClick
的事件處理程序方法。當(dāng)點(diǎn)擊按鈕時(shí),會(huì)觸發(fā)該方法并更新內(nèi)部狀態(tài)以反映當(dāng)前值。
然而,在每次渲染組件時(shí)都會(huì)創(chuàng)建新的 handleClick
方法實(shí)例可能會(huì)導(dǎo)致一定程度上的性能問(wèn)題。這就是為什么我們需要使用 useCallback
來(lái)進(jìn)行優(yōu)化。
使用 useCallback
來(lái)改寫后:
import React, { useState, useCallback } from "react";
function App() {
const [count, setCount] = useState(0);
const handleClick = useCallback(() => {
console.log("Clicked!");
setCount(count + 1);
}, [count]);
return (
<div>
<h2>Count: {count}</h2>
<button onClick={handleClick}>Increment</button>
</div>
);
}
export default App;
在上面的代碼中,我們使用了 useCallback
來(lái)緩存 handleClick
方法并根據(jù)需要更新它。這樣,在組件重新渲染時(shí)就不會(huì)創(chuàng)建新的實(shí)例,從而避免了性能問(wèn)題。
注意:第二個(gè)參數(shù) [count]
是依賴項(xiàng)數(shù)組。如果該值發(fā)生變化,則會(huì)觸發(fā)回調(diào)函數(shù)的重新計(jì)算和更新處理程序方法。
useMemo
作用
useMemo
,它可以幫助我們優(yōu)化性能并避免不必要的重新計(jì)算。
用法
首先,我們需要理解什么是記憶。在 JavaScript 中,如果兩個(gè)相同參數(shù)值之間存在對(duì)應(yīng)關(guān)系,則稱這些函數(shù)有“記憶”。因此,在進(jìn)行計(jì)算時(shí)使用已經(jīng)計(jì)算過(guò)的結(jié)果而不是再次運(yùn)行該函數(shù)以提高效率。
import React, { useState } from "react";
function App() {
const [count, setCount] = useState(0);
function fibonacci(n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
const result = fibonacci(count);
return (
<div>
<h2>Result: {result}</h2>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
export default App;
上面的代碼中展示了一個(gè)簡(jiǎn)單的斐波那契數(shù)列組件,并且定義了一個(gè)名為 fibonacci
的遞歸方法。每當(dāng)用戶點(diǎn)擊按鈕時(shí)都會(huì)調(diào)用該方法以更新內(nèi)部狀態(tài)以反映當(dāng)前值。
然而,在每次渲染組件時(shí)都會(huì)重新計(jì)算斐波那契數(shù)列可能會(huì)導(dǎo)致一定程度上的性能問(wèn)題。這就是為什么我們需要使用 useMemo
來(lái)進(jìn)行優(yōu)化。
改寫后如下所示:
import React, { useState, useMemo } from "react";
function App() {
const [count, setCount] = useState(0);
function fibonacci(n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
const result = useMemo(() => fibonacci(count), [count]);
return (
<div>
<h2>Result: {result}</h2>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
export default App;
在上面的代碼中,我們使用了 useMemo
來(lái)緩存斐波那契數(shù)列計(jì)算結(jié)果并根據(jù)需要更新它。這樣,在組件重新渲染時(shí)就不會(huì)重新計(jì)算該值,從而避免了性能問(wèn)題。
注意:第二個(gè)參數(shù) [count]
是依賴項(xiàng)數(shù)組。如果該值發(fā)生變化,則會(huì)觸發(fā)回調(diào)函數(shù)的重新計(jì)算和更新處理程序方法。
useRef
作用
useRef
它可以幫助我們?cè)诤瘮?shù)組件中保存可變值,并且不會(huì)導(dǎo)致組件重新渲染。
用法
import React, { useState } from "react";
function App() {
const [count, setCount] = useState(0);
function handleAlertClick() {
setTimeout(() => {
alert(`You clicked ${count} times`);
}, 3000);
}
return (
<div>
<h2>Count: {count}</h2>
<button onClick={() => setCount(count + 1)}>Increment</button>
<button onClick={handleAlertClick}>Show Alert</button>
</div>
);
}
export default App;
上面的代碼中展示了一個(gè)簡(jiǎn)單的計(jì)數(shù)器組件,并且定義了一個(gè)名為 handleAlertClick
的事件處理程序方法。當(dāng)用戶點(diǎn)擊“Show Alert”按鈕時(shí),該方法會(huì)等待三秒鐘然后顯示警告框以反映當(dāng)前值。
然而,在該三秒鐘內(nèi)如果用戶再次點(diǎn)擊“Increment”按鈕,則計(jì)數(shù)器將增加并且警告框仍將顯示舊的值。這就是因?yàn)槊看沃匦落秩窘M件時(shí)都創(chuàng)建了新的 count
變量實(shí)例。
改寫后如下所示:
import React, { useState, useRef } from "react";
function App() {
const [count, setCount] = useState(0);
const countRef = useRef(count);
function handleAlertClick() {
setTimeout(() => {
alert(`You clicked ${countRef.current} times`);
}, 3000);
}
return (
<div>
<h2>Count: {count}</h2>
<button onClick={() => setCount(count + 1)}>Increment</button>
<button onClick={handleAlertClick}>Show Alert</button>
</div>
);
}
export default App;
在上面的代碼中,我們使用了 useRef
來(lái)保存可變值,并且不會(huì)導(dǎo)致組件重新渲染。這樣,在每次重新渲染時(shí)都可以訪問(wèn)到最新的計(jì)數(shù)器值。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-512873.html
注意:需要將初始值傳遞給 useRef
,并通過(guò) .current
屬性來(lái)讀寫該值。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-512873.html
到了這里,關(guān)于React Hooks的講解與教程的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!