React hooks解析(useState、useEffect、userReducer、useCallback、useMemo、userContext、useRef)
什么是Hooks?
'Hooks'的單詞意思為“鉤子”。React Hooks 的意思是,組件盡量寫成純函數(shù),如果需要外部功能和副作用,就用鉤子把外部代碼"鉤"進(jìn)來。而React Hooks 就是我們所說的“鉤子”。
常用的鉤子
useState() useEffect() userReducer() useCallback() useMemo()
useContext()
useRef()
一、userState():狀態(tài)鉤子
純函數(shù)組件沒有狀態(tài),useState()用于為函數(shù)組件引入狀態(tài)。在useState()中,數(shù)組第一項(xiàng)為一個(gè)變量,指向狀態(tài)的當(dāng)前值。類似this.state,第二項(xiàng)是一個(gè)函數(shù),用來更新狀態(tài),類似setState。
import React, {useState} from 'react'
const AddCount = () => {
const [ count, setCount ] = useState(0)
return (
<div>
<button onClick={()=>setCount(count++)}>加一</button>
</>
)
}
export default AddCount
二、useEffect():副作用鉤子
useEffect()接受兩個(gè)參數(shù),第一個(gè)參數(shù)是你要進(jìn)行的異步操作,第二個(gè)參數(shù)是一個(gè)數(shù)組,用來給出Effect的依賴項(xiàng)。只要這個(gè)數(shù)組發(fā)生變化,useEffect()就會(huì)執(zhí)行
useEffect()可以看做componentDidMount,componentDidUpdate 和 componentWillUnmount這三個(gè)函數(shù)的組合。
useEffect(
() => {
const subscription = props.source.subscribe();
return () => {//相當(dāng)于ComponentWillUnmount
subscription.unsubscribe();
};
},
[props.source],//相當(dāng)于ComponentDidUpdate
);
三、useReducer():Action鉤子
我們通過用戶在頁面中發(fā)起action,從而通過reducer方法來改變state,從而實(shí)現(xiàn)頁面和狀態(tài)的通信。
const [state, dispatch] = useReducer(reducer, initialState)
它接受reducer函數(shù)和狀態(tài)的初始值作為參數(shù),返回一個(gè)數(shù)組,其中第一項(xiàng)為當(dāng)前的狀態(tài)值,第二項(xiàng)為發(fā)送action的dispatch函數(shù)。下面我們依然用來實(shí)現(xiàn)一個(gè)計(jì)數(shù)器。
const reduer = (state, action) => {
switch(action) {
case 'add': return state + 1;
case 'reduce': return state - 1;
case 'reset': return 0;
default:return state;
}
}
函數(shù)組件:
import React,{useReducer} from 'react'
export default function Counter() {
const [counter, dispatch] = useReducer(reduer, 0);
}
return (
<div >
<div>{counter}</div>
<Button onClick={() => dispatch('add')}>遞增</Button>
<Button onClick={() => dispatch('reduce')}>遞減</Button>
<Button onClick={() => dispatch('reset')}>重置</Button>
</div>
);
}
useState是useReducer的一個(gè)子集,useState 返回的函數(shù)內(nèi)部封裝了一個(gè) dispatch。useReducer( 單個(gè)組件中用的少,太重了)
官方的定義:在某些場景下,useReducer會(huì)比useState更適用,例如 state 邏輯較復(fù)雜且包含多個(gè)子值(注意且字),或者下一個(gè) state 依賴于之前的 state 等。
四、useCallback和useMemo
useMemo 和 useCallback 接收的參數(shù)都是一樣,第一個(gè)參數(shù)為回調(diào),第二個(gè)參數(shù)為要依賴的數(shù)據(jù)
共同作用:僅僅依賴數(shù)據(jù)發(fā)生變化, 才會(huì)調(diào)用,也就是起到緩存的作用。useCallback緩存函數(shù),useMemo 緩存返回值。
useCallback使用場景:
有一個(gè)父組件,其中包含子組件,子組件接收一個(gè)函數(shù)作為props;通常而言,如果父組件更新了,子組件也會(huì)執(zhí)行更新;所有依賴本地狀態(tài)或props來創(chuàng)建函數(shù),需要使用到緩存函數(shù)的地方,都是useCallback的應(yīng)用場景。
父組件:
import React, { useCallback } from 'react'
function ParentComp () {
// ...
const [ name, setName ] = useState('hi~')
// 每次父組件渲染,返回的是同一個(gè)函數(shù)引用
const changeName = useCallback((newName) => setName(newName), [])
return (
<div>
<button onClick={increment}>點(diǎn)擊次數(shù):{count}</button>
<ChildComp name={name} onClick={changeName}/>
</div>
);
}
子組件
import React, { memo } from 'react'
const ChildComp = memo(function ({ name, onClick }) {
console.log('render child-comp ...')
return <>
<div>Child Comp ... {name}</div>
<button onClick={() => onClick('hello')}>改變 name 值</button>
</>
})
點(diǎn)擊父組件按鈕,控制臺(tái)不會(huì)打印子組件被渲染的信息了。
究其原因:useCallback() 起到了緩存的作用,即便父組件渲染了,useCallback() 包裹的函數(shù)也不會(huì)重新生成,會(huì)返回上一次的函數(shù)引用。
useMemo
import React, { useCallback } from 'react'
function ParentComp () {
// ...
const [ name, setName ] = useState('hi~')
const [ age, setAge ] = useState(20)
const changeName = useCallback((newName) => setName(newName), [])
const info = { name, age } // 復(fù)雜數(shù)據(jù)類型屬性
return (
<div>
<button onClick={increment}>點(diǎn)擊次數(shù):{count}</button>
<ChildComp info={info} onClick={changeName}/>
</div>
);
}
父組件渲染,const info = { name, age }一行會(huì)重新生成一個(gè)新對(duì)象,導(dǎo)致傳遞給子組件的 info 屬性值變化,進(jìn)而導(dǎo)致子組件重新渲染。
function ParentComp () {
// ....
const [ name, setName ] = useState('hi~')
const [ age, setAge ] = useState(20)
const changeName = useCallback((newName) => setName(newName), [])
const info = useMemo(() => ({ name, age }), [name, age]) // 包一層
return (
<div>
<button onClick={increment}>點(diǎn)擊次數(shù):{count}</button>
<ChildComp info={info} onClick={changeName}/>
</div>
);
}
點(diǎn)擊父組件按鈕,控制臺(tái)中不再打印子組件被渲染的信息了。
五、useContext
React的useContext應(yīng)用場景:如果需要在組件A、B之間共享狀態(tài),可以使用useContext()。在它們的父組件上使用React的Context API,在組件外部建立一個(gè)Context。否則需要使用props一層層傳遞參數(shù)。
import React,{ useContext } from 'react'
const Ceshi = () => {
const AppContext = React.createContext({})
const A =() => {
const { name } = useContext(AppContext)
return (
<p>A{name}</p>
)
}
const B =() => {
const { name } = useContext(AppContext)
return (
<p>B{name}</p>
)
}
return (
<AppContext.Provider value={{name: 'hook測(cè)試'}}>
<A/>
<B/>
</AppContext.Provider>
)
}
export default Ceshi
顯示:Ahook測(cè)試,Bhook測(cè)試
六、useRef
只能為類組件定義ref屬性,而不能為函數(shù)組件定義ref屬性。想要在函數(shù)式組件中使用Ref,我們必須先了解兩個(gè)Api,useRef和forwardRef
1、返回一個(gè)可變的ref對(duì)象,該對(duì)象只有個(gè)current屬性,初始值為傳入的參數(shù)(initialValue)。 2、返回的ref對(duì)象在組件的整個(gè)生命周期內(nèi)保持不變 3、當(dāng)更新current值時(shí)并不會(huì)re-render,這是與useState不同的地方 4、更新useRef是side effect(副作用),所以一般寫在useEffect或event handler里 5、useRef類似于類組件的this
6、每個(gè)組件的 ref 只跟組件本身有關(guān),跟其他組件的 ref 沒有關(guān)系
import React, { useRef } from 'react'
const LikeButton: React.FC = () => {
let like = useRef(0)
function handleAlertClick() {
setTimeout(() => {
alert(`you clicked on ${like.current}`)
}, 3000)
}
return (
<>
<button
onClick={() => {like.current = like.current + 1}}>{like.current}贊</button>
<button onClick=handleAlertClick}>Alert</button>
</>
)
}
export default LikeButton
useRef與createRef的區(qū)別
組件依賴的props以及state狀態(tài)發(fā)生變更觸發(fā)更新時(shí),createRef每次都會(huì)返回個(gè)新的引用;而useRef不會(huì)隨著組件的更新而重新創(chuàng)建。
let refFromCreateRef = createRef()
可以通過useRef傳入子組件,調(diào)用子組件的方法。
forwardRef:將ref父類的ref作為參數(shù)傳入函數(shù)式組件中
const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} className="FancyButton">
{props.children}
</button>
));
// 可以直接獲取到button的DOM節(jié)點(diǎn)
const ref = React.useRef();
<FancyButton ref={ref}>Click me!</FancyButton>;
useImperativeHandle在函數(shù)式組件中,用于定義暴露給父組件的ref方法,用來限制子組件對(duì)外暴露的信息。
只有useImperativeHandle第二個(gè)參數(shù)定義的屬性跟方法可以在父組件能夠獲取到。
function FancyInput(props, ref) {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));
return <input ref={inputRef} ... />;
}
FancyInput = forwardRef(FancyInput);
//渲染 <FancyInput ref={inputRef} /> 的父組件
//可以調(diào)用 inputRef.current.focus()
參考:
https://www.jianshu.com/p/d600f749bb19
https://www.jianshu.com/p/014ee0ebe959
https://blog.csdn.net/u011705725/article/details/115634265
總結(jié)
以上是生活随笔為你收集整理的React hooks解析(useState、useEffect、userReducer、useCallback、useMemo、userContext、useRef)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 三国志战棋版毒召阵容搭配攻略
- 下一篇: 实况王者集结阵容搭配推荐