前言
最近的換寫React項目了,好久沒有寫React酒甸,還動不動就想class??堆巧,現(xiàn)在跟上時代礁叔,重新學(xué)習(xí)React Hook.Hook 是 React 16.8 的新增特性牍颈。它可以讓你在不編寫 class 的情況下使用 state 以及其他的 React 特性。
為什么有Hook琅关?
1煮岁、在組件之間復(fù)用狀態(tài)邏輯比較難,需要用到高階組件或者render props死姚,Hook可以無需修改組件結(jié)構(gòu)的情況下人乓,復(fù)用狀態(tài)邏輯。
2都毒、Hook可以將組件中相互關(guān)聯(lián)的部分拆分成更小的函數(shù)色罚,方便理解;
3账劲、不再使用class和this戳护,更方便上手和理解;
使用Hook的注意事項
1瀑焦、只能在最外層函數(shù)中調(diào)用Hook腌且。(不要在循環(huán)、條件判斷榛瓮、子函數(shù)中調(diào)用)
React在創(chuàng)建hook時铺董,以鏈表的解構(gòu)存儲,前一個hook中next指針指向下一個hook禀晓。在組件更新時會進行hook的一一對應(yīng)的比對精续,所以要保證每次hook數(shù)量一致,位置相同粹懒。循環(huán)重付、條件判斷中使用hook,會導(dǎo)致數(shù)量和位置的變化凫乖,產(chǎn)生錯誤确垫。
2弓颈、只在react的函數(shù)組件中調(diào)用。
常用的HooK
1.useState
- 作用:在組件內(nèi)部添加一個state删掀,React會在重復(fù)渲染時保留這個state翔冀。
- 參數(shù): 1個,state的初始值initialState爬迟;
const [state,setState] =useState(initialState)
- 返回值 :2個
1)state 當(dāng)前狀態(tài)橘蜜,在初始渲染時菊匿,state就是initialState
2)setState更新當(dāng)前state的函數(shù)付呕,他接受一個新的state,并且將該組件的一次渲染加入隊列跌捆,他有點類似類組件中this.setState,但并不會將新舊state合并
//在函數(shù)組件中
const [state,setState] =useState({name:"lily",age:18})
return(
<button onclick={setState({age:20})}>改變年齡<button>
//這里使用useState不會將新舊state徽职,現(xiàn)在state為{age:20},name屬性就沒有了
//所以需要注意 onclick={setState({...state,age:20})}
)
- 特點
1) 每次渲染都是獨立的閉包佩厚,擁有當(dāng)前自己的props\state\函數(shù)
2)函數(shù)式更新
//如果新的狀態(tài)需要依賴舊的狀態(tài)姆钉,可以使用函數(shù)式更新
setState(state =>({...state,age:state.age +1}))
//將舊狀態(tài)傳入,返回新的狀態(tài)
3)懶加載初始化state
//如果state中的值需要復(fù)雜計算
const [state,setState] =useState(()=> ({name:"lily",age:12}))
- 性能優(yōu)化(減少渲染次數(shù))
1)Object.is
在調(diào)用state的更新函數(shù)時抄瓦,React會先進行Object.is的比較算法
如果state不相同潮瓶,進行子組件渲染和effect,否則不進行刷新渲染
2)useMemo(緩存值)
某些情況下組件中的值需要依賴state進行計算后得到钙姊,由于每次組件更新都會去重新計算毯辅,為了減少性能消耗,可以使用useMemo緩存值煞额,僅僅當(dāng)依賴改變時,才重新計算。
- 參數(shù):計算函數(shù)嗜暴,依賴數(shù)組
則函數(shù)僅會在某個依賴項改變時才重新計算memoized 值绰更。
const [count, setCount] = useState(0);
//expensive 需要依賴count計算得到
const expensive = useMemo(() => {
let sum = 0;
for (let i = 0; i < count; i++) {
sum += i;
}
return sum;
//只有count變化,這?才重新執(zhí)?
}, [count]);
3)useCallback (緩存回調(diào)函數(shù))
由于每次組件更新都會內(nèi)部函數(shù)都會重新創(chuàng)建一次婚温,為了節(jié)省性能描焰,可以使用useCallback,使內(nèi)聯(lián)回調(diào)函數(shù)僅僅在傳入依賴項改變時進行更新栅螟。
- 參數(shù):內(nèi)聯(lián)回調(diào)函數(shù)荆秦,依賴數(shù)組
則函數(shù)僅會在某個依賴項改變時才進行更新。
const [count, setCount] = useState(0);
const addClick = useCallback(() => {
setCount(count+1)
}, [count]);
4)memo (緩存組件)
父組件更新子組件也會重新創(chuàng)建嵌巷,為節(jié)省性能萄凤,可用memo將子組件緩存,僅僅當(dāng)props改變時搪哪,組件才進行更新
const Child = (props)=>{
return <div>{props.age}</div>
}
//這里只會在props改變的時候重新渲染
Child =memo(Child)
const Father=()=>{
const [name,setName]=useState("lily")
const [age,setAge]=useState(18)
return(
<>
<button onclick={setAge(age+1)}>改變年齡<button>
<input onChange={e=>(setName(e.target.value))}>改變姓名<button>
<Child age={age}/>
</>
)
}
5)useRef (緩存ref)
同理靡努,用useRef可對React.creactRef對象進緩存
2. useReducer
- 作用:編寫自定義hook或者在某些改變state邏輯復(fù)雜的情況下替代useState,用法類似redux,useState是useReducer的語法糖惑朦。
- 參數(shù): 3個兽泄,reducer方法 、initialState初始值漾月,init病梢;
const [state,dispatch] =useReducer(reducer ,initialState)
返回值 :2個
1)state當(dāng)前狀態(tài)梁肿,在初始渲染時蜓陌,state就是initialState
2)dispatch派發(fā)方法,接受參數(shù)action吩蔑,改變當(dāng)前state钮热,并且將該組件的一次渲染加人隊列。自定義hook
//實現(xiàn)一個useState
const useState=(initalState)=>{
const reducer = useCallback(_state,action)=>{
return action.paylaod
}
const [state,dispatch] = useReducer(reducer, initalState)
const setState = (state)=>{
dispatch({paylaod:state})
}
return [state,setState]
}
3.useContext
- 作用:提供更方便的方法從React上下文中拿到consumer的值
參數(shù): 1個烛芬,context(React.createContext)隧期;
const value=useContext(context)
- 返回值 :1個 consumer的值
4.useEffect
- 作用:在React渲染階段,改變DOM赘娄、添加訂閱仆潮、設(shè)置定時器等操作會破壞UI一致性,含有副作用的操作將不被允許遣臼,使用useEffect完成副作用的操作性置,傳入函數(shù)會在組件渲染后執(zhí)行.
- 參數(shù): 2個,didUpdate包含副作用的回調(diào)函數(shù)暑诸,在組件渲染后執(zhí)行,[state]依賴項蚌讼,傳入依賴項,僅在依賴項改變后的執(zhí)行
useEffect(didUpdate,[state])
- 返回值 :1個 清除副作用函數(shù)个榕,在組件銷毀前執(zhí)行篡石,相當(dāng)于componentWillUnmount,可進行定時器西采,事件監(jiān)聽的移除操作
- 特點
由于useEffect的副作用函數(shù)在組件渲染后執(zhí)行凰萨,他和class組件中的 生命周期componentDidMount/componentDidUpdate和componentWillUnmount有相同的用途
5.useRef、useImperativeHandle
- useRef作用:對ref對象進緩存械馆,ref 對象在組件的整個生命周期內(nèi)保持不變胖眷。
- 參數(shù): 1個,initialValue霹崎,ref.curren初始化的值
function FocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
// `current` 指向已掛載到 DOM 上的文本輸入元素
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
- useImperativeHandle作用:有些情況下我們需要父組件把ref傳遞給子組件珊搀,僅僅使用forwardRef將子組件的ref屬性都暴露給父組件是危險的,也違反了封裝原則尾菇,useImperativeHandle允許在子組件中把自定義實例附加到父組件傳過來的ref上境析,減少暴露給父組件的屬性
- 參數(shù): 3個囚枪,ref, createHandle處理函數(shù),其返回值會替換父組件傳來的ref.current, [state]依賴項
useImperativeHandle(ref, createHandle, [state])
- 例子
let Child = (props, ref) =>{
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus()
}
}));
return <input ref={inputRef} />;
}
Child = forwardRef(Child );
const Father=() => {
const ref = useRef(null);
return (
<>
<Child ref={ref}/>
<button onClick={()=>{ ref.current.focus()}}>聚焦</button >
</>
)
}
6.useLayoutEffect
- 作用 :與useEffect相同劳淆,都是用來執(zhí)行副作用链沼。
- 特點 :useEffect是在渲染之后調(diào)用effect,也就是下一楨執(zhí)行沛鸵,是異步的括勺;
而useLayoutEffect在當(dāng)前幀Render tree計算布局(Layout)信息后,渲染前曲掰,同步調(diào)用effect疾捍。官方文檔建議使用標(biāo)準(zhǔn)useEffec。
7.自定義Hook
- 定義:函數(shù)以use開頭并且在函數(shù)內(nèi)部調(diào)用其他hooks蜈缤,并且返回一個數(shù)組拾氓,可以實現(xiàn)邏輯復(fù)用冯挎。
- 例子 :
//實現(xiàn)一個thunk
const useThunk =(reducer,initalState)=>{
const [state,dispatch] =useReducer(reducer,initalState)
const thunkDispatch = (action)=>{
if( action instanceof Function){ //如果action是函數(shù)底哥,傳入新的dispatch執(zhí)行action
return action (thunkDispatch,()=>state)
}else{
dispatch(action )
}
return [state,thunkDispatch]
}
結(jié)尾
現(xiàn)在就只了解到這么多。還有什么沒寫到的日后更新房官。