React Hooks
什么是Hooks
Hooks是一個新的react特性提案,適用于函式式組件(視圖組件),如果需要外部react特性(比如狀態管理、生命周期),就用鉤子把外部特性“鉤”進來,典型標志是函式名字都是以use開頭,
hooks出現的背景
- 跨組件復用stateful logic十分困難 使用Hooks,你可以在將含有state的邏輯從組件中抽象出來,這將可以讓這些邏輯容易被測驗,同時,Hooks可以幫助你在不重寫組件結構的情況下復用這些邏輯,
- 復雜的組件難以理解 Hooks允許您根據相關部分(例如設定訂閱或獲取資料)將一個組件分割成更小的函式,而不是強制基于生命周期方法進行分割
- 不止是用戶,機器也對Classes難以理解 Hooks讓你可以在classes之外使用更多React的新特性
常用hooks
- useState
let [count, setCount] = useState(100);
- useEffect
useEffect(()=>{
return ()=>{}
}, [])

- useLayoutEffect
- useEffect 在全部渲染完畢后才會執行
- useLayoutEffect 會在 瀏覽器 layout 之后,painting 之前執行
- 其函式簽名與 useEffect 相同,但它會在所有的 DOM 變更之后同步呼叫 effect
- 可以使用它來讀取 DOM 布局并同步觸發重渲染
- 在瀏覽器執行繪制之前 useLayoutEffect 內部的更新計劃將被同步重繪
- 會阻塞頁面的渲染,如果在里面執行耗時任務的話,頁面就會卡頓
- useContext 直接獲取祖先元素通過createContext創建的context;
- useReducer
const [state, dispatch] = useReducer(reducer, initialState, init);
- memo,useMemo和useCallback在優化組件的應用場景
- 在子組件不需要父組件值和函式的情況下,使用memo包裹即可
- 如果是函式作為props,可以使用useCallback保證不會反復修改
- 如果是值作為props,可以使用useMemo保證值不會反復修改
- useRef
不符合capture values,本身不會變化,存盤的.current會變化 - useImperativeHandle
配合forwardRef使用,用于自定義通過ref給父組件暴露的值 - useDebugValue
用于開發者工具除錯
封裝自定義Hooks
封裝hooks獲取視窗大小
// useWinSize
import React, { useState ,useEffect ,useCallback } from 'react';
export default function useWinSize(){
const [ size , setSize] = useState({
width:document.documentElement.clientWidth,
height:document.documentElement.clientHeight
})
const onResize = useCallback(()=>{
setSize({
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight
})
},[])
useEffect(()=>{
window.addEventListener('resize',onResize)
return ()=>{
window.removeEventListener('resize',onResize)
}
},[])
return size;
}
// demo.js
import useWinSize from './useWinSize'
export default function(){
const size = useWinSize()
return (
<div>頁面Size:{size.width}x{size.height}</div>
)
}
延遲設定值
import React, {useState, useRef, useEffect} from 'react'
export const useDelayState = (initialState)=>{
const [state, setState] = useState(initialState);
const ref = useRef();
const delaySetState = (value, delay)=>{
ref.current = setTimeout(()=>{
setState(value)
}, delay)
}
useEffect(()=>{
return ()=>{
clearTimeout(ref.current)
}
}, [])
return [state, delaySetState, setState]
}
GeoLocation獲取地理定位
import { useEffect, useState } from 'react';
const useGeolocation = options => {
const [state, setState] = useState({
loading: true,
accuracy: null,
altitude: null,
altitudeAccuracy: null,
heading: null,
latitude: null,
longitude: null,
speed: null,
timestamp: Date.now(),
});
let mounted = true;
let watchId: any;
const onEvent = event => {
if (mounted) {
setState({
loading: false,
accuracy: event.coords.accuracy,
altitude: event.coords.altitude,
altitudeAccuracy: event.coords.altitudeAccuracy,
heading: event.coords.heading,
latitude: event.coords.latitude,
longitude: event.coords.longitude,
speed: event.coords.speed,
timestamp: event.timestamp,
});
}
};
const onEventError = (error) =>
mounted && setState(oldState => ({ ...oldState, loading: false, error }));
useEffect(() => {
navigator.geolocation.getCurrentPosition(onEvent, onEventError, options);
watchId = navigator.geolocation.watchPosition(onEvent, onEventError, options);
return () => {
mounted = false;
navigator.geolocation.clearWatch(watchId);
};
}, []);
return state;
};
export default useGeolocation;
Hooks的使用注意事項
- 只能在頂層呼叫Hooks? Hooks是使用陣列或單鏈表串聯起來,Hooks順序修改會打亂執行結果
- useState在多個組件中引入,彼此之間會不會有影響? 在React中Hooks把資料存在fiber node上的,每個組件都有自己的currentlyRenderingFiber.memoizedState
Hooks的問題
- Hooks能解決組件狀態的復用問題,但沒有很好的解決JSX復用問題
- React Hooks模糊了生命周期的概念,但也帶來了更高門檻的學習(Hooks生命周期的理解、Hooks Rules的理解、useEffect依賴項的判斷等)
- 類擁有比函式更豐富的表達能力(OOP),Function Component容易使代碼邏輯混亂
Hooks的原理
- 單向鏈表通過next把hooks串聯起來
- memoizedState存在fiber node上,組件之間不會相互影響
- useState和useReducer中通過dispatchAction調度更新任務
如何插入一段漂亮的代碼片
去博客設定頁面,選擇一款你喜歡的代碼片高亮樣式,下面展示同樣高亮的 代碼片.
// An highlighted block
var foo = 'bar';
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/18991.html
標籤:其他
