React Hook用法示例詳解(6個常見hook)
1、useState:讓函式式元件擁有狀態
用法示例:
// 計數器 import { useState } from 'react' const Test = () => { const [count,setCount] = useState(0); return ( <> <h1>點選了{count}次</h1> <button onClick={() => setCount(count + 1)}>+1</button> </> ); } export default Test
PS:class元件中this.setState更新是state是合併, useState中setState是替換。例如:
// 錯誤示例 import { useState } from 'react' const Test = () => { const [counts,setCounts] = useState({ num1: 0,num2: 0 }); return ( <> <h1>num1:{counts.num1}</h1> <h1>num2:{counts.num2}</h1> <button onClick={() => setCounts({ num1: counts.num1 + 1})}>num1+1</button> <button onClick={() => setCounts({ num2: counts.num2 + 1})}>num2+1</button> </> ); } export default Test
可以看到useState中setState是替換,不會合並,正確更新:
import { useState } from 'react' const Test = () => { const [counts,num2: 0 }); return ( <> <h1>num1:{counts.num1}</h1> <h1>num2:{counts.num2}</h1> <button onClick={() => setCounts({ ...counts,num1: counts.num1 + 1})}>num1+1</button> <button onClick={() => setCounts({ ...counts,num2: counts.num2 + 1})}>num2+1</button> </> ); } export default Test
2、useEffect:副作用,取代生命週期
用法示例,在class元件中如果需要在元件掛載後和資料更新後做同一件事,我們會這樣做:
componentDidMount() { // 做一些事 } componentDidUpdate() { // 做一些事 }
可以看出來,如果邏輯複雜後,程式碼看起來不優雅,且容易造成邏輯混亂,而使用useEffect:
useEffect(() => { // 做一些事 });
此刻已經看到了useEffect的基本用法,除此之外,他還可以繫結觸發更新的依賴狀態,預設是狀態中任何資料發生變化副作用都會執行,如:
import { useState,useEffect } from 'react' const Test = () => { const [count1,setCount1] = useState(0); const [count2,setCount2] = useState(0); useEffect(() => { console.log('useEffect觸發了') }); return ( <> <h1>count1:{count1}</h1> <h1>count2:{count2}</h1> <button onClick={() => setCount1(count1 + 1)}>count1+1</button> <button onClick={() => setCount2(count2 + 1)}>count2+1</button> </> ); } export default Test
將上述程式碼useEffect第二個引數傳入需要繫結的狀態,可繫結多個:
// 語法:useEffect(回撥函式,[依賴值]) useEffect(() => { console.log('useEffect觸發了') },[count1]);
可以看到,只有繫結的count1發生變化才會觸發,如果傳空陣列則任何狀態發生變化都不會觸發,此時useEffect的作用就類似class元件中的componentDidMount,所以傳送請求通常也會在此執行。
清理副作用
在上面的操作中都不用清理的副作用,然而,有些副作用是需要去清理的,不清理會造成異常甚至記憶體洩漏,比如開啟定時器,如果不清理,則會多次開啟,從上面可以看到useEffect的第一個引數是一個回撥函式,可以在回撥函式中再返回一個函式,該函式可以在狀態更新後第一個回撥函式執行之前呼叫,具體實現:
useEffect(() => { // 設定副作用 return () => { // 清理副作用 } });
3、useContext:跨元件共享資料
React.createContext();建立一個TestContext物件
TestContext.Provider包裹子元件
資料放在<TestContext.Provider value={value}>的value中
子元件中通過useContext(TestContext)獲取值
import React,{ useContext,useState } from 'react'; const TestContext = React.createContext(); const Parent = () => { const [value,setValue] = useState(0); return ( <div> {(() => console.log("Parent-render"))()} <button onClick={() => setValue(value + 1)}>value + 1</button> <TestContext.Provider value={value}> <Child1 /> <Child2 /> </TestContext.Provider> </div> ); } const Child1 = () => { const value = useContext(TestContext); return ( <div> {(() => console.log('Child1-render'))()} <h3>Child1-value: {value}</h3> </div> ); } const Child2 = () => { return ( <div> {(() => console.log('Child2-render'))()} <h3>Child2</h3> </div> ); } export default Parent
至此資料實現共享了,但是可以看到在TestContext中的共享資料只要發生變化,子元件都會重新渲染,Child2並沒有繫結資料,不希望他做無意義的渲染,可以使用React.memo解決,實現:
const Child2 = React.memo(() => { return ( <div> {(() => console.log('Child2-render'))()} <h3>Child2</h3> </div> ); });
4、useCallback:效能優化
語法:
// useCallback(回撥函式,[依賴值]) const handleClick = useCallback(()=> { // 做一些事 },[value]);
useCallback返回的是一個 memoized(快取)函式,在依賴不變的情況下,多次定義的時候,返回的值是相同的,他的實現原理是當使用一組引數初次呼叫函式時,會快取引數和計算結果,當再次使用相同的引數呼叫該函式時,會直接返回相應的快取結果http://www.cppcns.com。
優化效能例子:
import React,{ useState,useCallback,memo } from 'react'; const Parent = () => { const [value1,setValue1] = useState(0); const [value2,setValue2] = useState(0); const handleClick1 = useCallback(()=> { setValue1(value1 + 1); },[value1]); const handleClick2 = useCallback(()=> { setValue2(val程式設計客棧ue2 + 1); },[value2]); return ( <> {(() => console.log("Parent-render"))()} <h3>{value1}</h3> <h3>{value2}</h3> <Child1 handleClick1={handleClick1} /> <Child2 handleClick2={handleClick2} /> </> ); } const Child1 = memo(props => { return ( <div> 程式設計客棧 {(() => console.log("Child1-render"))()} <button onClick={() => props.handleClick1()}>value1 + 1</button> </div> ); }); const Child2 = memo(props => { return ( <div> {(() => console.log("Child2-render"))()} <butwww.cppcns.comton onClick={() => props.handleClick2()}>value2 + 1</button> </div> ); }); export default Parent
useCallback返回的是一個memoized回撥函式,僅在其中繫結的一個依賴項變化後才更改可防止不必要的渲染,在跨元件共享資料中舉例的事件是在父元件中點選觸發,而現在是使用狀態提升,在父元件中傳遞方法供子元件呼叫,每次render時函式也會變化,導致子元件重新渲染,上面例子useCallback將函式進行包裹,依賴值未發生變化時會返回快取的函式,配合React.memo即可優化無意義的渲染。
5、useMemo:效能優化
語法:
// useMemo(回撥函式,[依賴值]) useMemo(() => { // 做一些事情 },[value]);
先看一個例子:
import React,{ useState } from 'react' const Test = ()=> { const [value,setValue] = useState(0); const [count,setCount] = useState(1); const getDoubleCount = () => { consoOupoPle.log('getDoubleCount進行計算了'); return count * 2; }; return ( <div> <h2>value: {value}</h2> <h2>doubleCount: {getDoubleCount()}</h2> <button onClick={() => setValue(value + 1)}>value+1</button> </div> ) } export default Test
可以看到getDoubleCount依賴的是count,但value發生變化它也重新進行了計算渲染,現在只需要將getDoubleCount使用useMemo進行包裹,如下:
import React,useMemo } from 'react' const Test = ()=> { const [value,setCount] = useState(1); const getDoubleCount = useMemo(() => { console.log('getDoubleCount進行計算了'); return count * 2; },[count]); return ( <div> <h2>value: {value}</h2> <h2>doubleCount: {getDoubleCount}</h2> <button onClick={() => setValue(value + 1)}>value+1</button> </div> ) } export default Test
現在getDoubleCount只有依賴的count發生變化時才會重新計算渲染。
useMemo和useCallback的共同點:
- 接收的引數都是一樣的,第一個是回撥函式,第二個是依賴的資料
- 它們都是當依賴的資料發生變化時才會重新計算結果,起到了快取作用
useMemo和useCallback的區別:
- useMemo計算結果是return回來的值,通常用於快取計算結果的值
- useCallback計算結果是一個函式,通常用於快取函式
6、useRef用法:例如要實現點選button按鈕使input輸入框獲得焦點:
import React,[count]); return ( <div> <h2>value: {value}</h2> <h2>doubleCount: {getDoubleCount}</h2> <button onClick={() => setValue(value + 1)}>value+1</button> </div> ) } export default Test
這樣看起來非常像React.createRef(),將上面程式碼中的useRef()改成React.createRef()也能實現同樣的效果,那為什麼要設計一個新的hook?難道只是會了加上use,統一hook規範?
事實上,它們確實不一樣。
官網的說明如下:
useRef returns a mutable ref object whose .current property is initialized to the passed
argument (initialValue). The returned object will persist for the full lifetime of the component.
翻譯:
簡單來說,useRef就像一個儲物箱,你可以隨意存放任何東西,再次渲染時它會去儲物箱找,createRef每次渲染都會返回一個新的引用,而useRef每次都會返回相同的引用。
到此這篇關於React Hook用法詳解(6個常見hook)的文章就介紹到這了,更多相關React Hook用法內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!