React Hook用法示例詳解(6個常見hook)
1、useState:讓函數(shù)式組件擁有狀態(tài)
用法示例:
// 計數(shù)器 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, setCounts] = useState({ num1: 0, 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組件中如果需要在組件掛載后和數(shù)據(jù)更新后做同一件事,我們會這樣做:
componentDidMount() { // 做一些事 } componentDidUpdate() { // 做一些事 }
可以看出來,如果邏輯復(fù)雜后,代碼看起來不優(yōu)雅,且容易造成邏輯混亂,而使用useEffect:
useEffect(() => { // 做一些事 });
此刻已經(jīng)看到了useEffect的基本用法,除此之外,他還可以綁定觸發(fā)更新的依賴狀態(tài),默認是狀態(tài)中任何數(shù)據(jù)發(fā)生變化副作用都會執(zhí)行,如:
import { useState, useEffect } from 'react' const Test = () => { const [count1, setCount1] = useState(0); const [count2, setCount2] = useState(0); useEffect(() => { console.log('useEffect觸發(fā)了') }); 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第二個參數(shù)傳入需要綁定的狀態(tài),可綁定多個:
// 語法:useEffect(回調(diào)函數(shù),[依賴值]) useEffect(() => { console.log('useEffect觸發(fā)了') }, [count1]);
可以看到,只有綁定的count1發(fā)生變化才會觸發(fā),如果傳空數(shù)組則任何狀態(tài)發(fā)生變化都不會觸發(fā),此時useEffect的作用就類似class組件中的componentDidMount,所以發(fā)送請求通常也會在此執(zhí)行。
清理副作用
在上面的操作中都不用清理的副作用,然而,有些副作用是需要去清理的,不清理會造成異常甚至內(nèi)存泄漏,比如開啟定時器,如果不清理,則會多次開啟,從上面可以看到useEffect的第一個參數(shù)是一個回調(diào)函數(shù),可以在回調(diào)函數(shù)中再返回一個函數(shù),該函數(shù)可以在狀態(tài)更新后第一個回調(diào)函數(shù)執(zhí)行之前調(diào)用,具體實現(xiàn):
useEffect(() => { // 設(shè)置副作用 return () => { // 清理副作用 } });
3、useContext:跨組件共享數(shù)據(jù)
React.createContext();創(chuàng)建一個TestContext對象
TestContext.Provider包裹子組件
數(shù)據(jù)放在<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
至此數(shù)據(jù)實現(xiàn)共享了,但是可以看到在TestContext中的共享數(shù)據(jù)只要發(fā)生變化,子組件都會重新渲染,Child2并沒有綁定數(shù)據(jù),不希望他做無意義的渲染,可以使用React.memo解決,實現(xiàn):
const Child2 = React.memo(() => { return ( <div> {(() => console.log('Child2-render'))()} <h3>Child2</h3> </div> ); });
4、useCallback:性能優(yōu)化
語法:
// useCallback(回調(diào)函數(shù),[依賴值]) const handleClick = useCallback(()=> { // 做一些事 }, [value]);
useCallback返回的是一個 memoized(緩存)函數(shù),在依賴不變的情況下,多次定義的時候,返回的值是相同的,他的實現(xiàn)原理是當(dāng)使用一組參數(shù)初次調(diào)用函數(shù)時,會緩存參數(shù)和計算結(jié)果,當(dāng)再次使用相同的參數(shù)調(diào)用該函數(shù)時,會直接返回相應(yīng)的緩存結(jié)果。
優(yōu)化性能例子:
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(value2 + 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"))()} <button onClick={() => props.handleClick2()}>value2 + 1</button> </div> ); }); export default Parent
useCallback返回的是一個memoized回調(diào)函數(shù),僅在其中綁定的一個依賴項變化后才更改可防止不必要的渲染,在跨組件共享數(shù)據(jù)中舉例的事件是在父組件中點擊觸發(fā),而現(xiàn)在是使用狀態(tài)提升,在父組件中傳遞方法供子組件調(diào)用,每次render時函數(shù)也會變化,導(dǎo)致子組件重新渲染,上面例子useCallback將函數(shù)進行包裹,依賴值未發(fā)生變化時會返回緩存的函數(shù),配合React.memo即可優(yōu)化無意義的渲染。
5、useMemo:性能優(yōu)化
語法:
// useMemo(回調(diào)函數(shù),[依賴值]) useMemo(() => { // 做一些事情 },[value]);
先看一個例子:
import React, { useState } from 'react' const Test = ()=> { const [value, setValue] = useState(0); const [count, setCount] = useState(1); const getDoubleCount = () => { console.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發(fā)生變化它也重新進行了計算渲染,現(xiàn)在只需要將getDoubleCount使用useMemo進行包裹,如下:
import React, { useState, useMemo } from 'react' const Test = ()=> { const [value, setValue] = useState(0); const [count, 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
現(xiàn)在getDoubleCount只有依賴的count發(fā)生變化時才會重新計算渲染。
useMemo和useCallback的共同點:
- 接收的參數(shù)都是一樣的,第一個是回調(diào)函數(shù),第二個是依賴的數(shù)據(jù)
- 它們都是當(dāng)依賴的數(shù)據(jù)發(fā)生變化時才會重新計算結(jié)果,起到了緩存作用
useMemo和useCallback的區(qū)別:
- useMemo計算結(jié)果是return回來的值,通常用于緩存計算結(jié)果的值
- useCallback計算結(jié)果是一個函數(shù),通常用于緩存函數(shù)
6、useRef用法:例如要實現(xiàn)點擊button按鈕使input輸入框獲得焦點:
import React, { useState, useMemo } from 'react' const Test = ()=> { const [value, setValue] = useState(0); const [count, 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
這樣看起來非常像React.createRef(),將上面代碼中的useRef()改成React.createRef()也能實現(xiàn)同樣的效果,那為什么要設(shè)計一個新的hook?難道只是會了加上use,統(tǒng)一hook規(guī)范?
事實上,它們確實不一樣。
官網(wǎng)的說明如下:
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每次都會返回相同的引用。
到此這篇關(guān)于React Hook用法詳解(6個常見hook)的文章就介紹到這了,更多相關(guān)React Hook用法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
react-native聊天室|RN版聊天App仿微信實例|RN仿微信界面
這篇文章主要介紹了react-native聊天室|RN版聊天App仿微信實例|RN仿微信界面,需要的朋友可以參考下2019-11-11concent漸進式重構(gòu)react應(yīng)用使用詳解
這篇文章主要為大家介紹了concent漸進式重構(gòu)react應(yīng)用的使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-11-11利用React高階組件實現(xiàn)一個面包屑導(dǎo)航的示例
這篇文章主要介紹了利用React高階組件實現(xiàn)一個面包屑導(dǎo)航的示例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08react Input組件Compositionstart和Compositionend事件
這篇文章主要為大家介紹了Compositionstart和Compositionend事件之于react組件庫Input組件的坑解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-11-11React Native自定義標(biāo)題欄組件的實現(xiàn)方法
今天講一下如何實現(xiàn)自定義標(biāo)題欄組件,我們都知道RN有一個優(yōu)點就是可以組件化,在需要使用該組件的地方直接引用并傳遞一些參數(shù)就可以了,這種方式確實提高了開發(fā)效率。對React Native自定義標(biāo)題欄組件的實現(xiàn)方法感興趣的朋友參考下2017-01-01react-router實現(xiàn)跳轉(zhuǎn)傳值的方法示例
這篇文章主要給大家介紹了關(guān)于react-router實現(xiàn)跳轉(zhuǎn)傳值的相關(guān)資料,文中給出了詳細的示例代碼,對大家具有一定的參考學(xué)習(xí)價值,需要的朋友們下面跟著小編一起來學(xué)習(xí)學(xué)習(xí)吧。2017-05-05