本文主要記錄 Hook
中比較重要的知識點以及實際應用中遇到的問題,還有查閱相關文檔使用的一些心得html
若是文章中有出現紕漏、錯誤之處,還請看到的小夥伴多多指教,先行謝過前端
如下↓react
Hook 是 React 16.8 的新增特性。它可讓你在不編寫 class 的狀況下使用 state 以及其餘的 React 特性
雖然在學習 Hook
的過程當中瞭解 class
組件並非必須的,可是若是你想更快更容易地理解 Hook
仍是須要先了解 class
組件的,由於不管是 官網 仍是其餘大部分文檔在介紹 Hook
的時候都是經過與 class
組件對比的git
至於爲何會有 Hook
,它解決了咱們開發中的什麼問題,這不在本文的記錄範圍內,感興趣的朋友能夠 參考這裏github
import React, { useState, useEffect } from 'react'; function Example() { // 聲明一個叫 「count」 的 state 變量。 const [count, setCount] = useState(0); useEffect(()=> { console.log('加載了…') return () => { console.log('解綁了…') } }) return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }
上面是一個簡單的 Hook
,當咱們點擊按鈕的時候,頁面上的數字書遞增,同時控制檯也會打印出不一樣的信息web
最直觀的感受,咱們不再須要定義 class
類來使用 state
維護組件自身的狀態了,而是使用 useState
來生成組件的 state
和控制它的方法。一樣的沒有藉助組件的生命週期,咱們註冊在 useEffect
中的方法在首次加載和 state
更新的時候也執行了數組
在這裏,useState
與 useEffect
就是 不一樣的 Hook
。經過在函數中調用不一樣的 Hook
,就能夠實現使用 class
實現的一些功能瀏覽器
Hook
是一些能夠在函數組件裏鉤入React state
及生命週期等特性的函數。不能在 class
組件中使用Hook
。不要在循環、條件判斷或者子函數中調用React
的函數組件或自定義 Hook
中調用 Hook
Hook
是一種複用狀態邏輯的方式,它不復用 state
自己,Hook
的每次調用都有一個徹底獨立的 state
,簡單來講就是一個新的 state
Hook
使用了 JavaScript
的閉包機制瞭解 Hook
的這些特性,對於咱們熟悉並使用 Hook
會有很大的幫助緩存
推薦閱讀 爲何 順序調用對 React Hook 很重要性能優化
const [state, setState] = useState(initialState)
特性:
useState
是一個函數,返回值是一個數組(當前 state
以及更新 state
的函數), 惟一的參數就是初始 state
state
) 與傳入的第一個參數值相同setState
函數用於更新 state
。它接收一個新的 state
值並將組件的一次從新渲染加入隊列initialState
只會在初識渲染中起做用,後續會被忽略,若是傳入一個函數就只會在初始渲染時被調用,若是爲空,變量的值就是 undefined
const [name, setName] = useState() name // undefined // 這個函數只會執行一次 const [count, setCount] =useState(()=> { const initialState = someExpensiveComputation(props); return initialState; })
state
變量老是替換它而不是合併它,this.setstate()
會自動合併// 好比咱們修改 state 中的某一個屬性 const [state, setState] = useState({ name: '遊蕩de蝌蚪', age: 18, hobby: 'play game' }) // 使用 class this.setstate({ age: 17 }) // 使用 Hook setState(prevState => { return {...prevState, age: 17} })
另外,在使用 useState
聲明變量的時候,咱們能夠單獨聲明每個變量,也能夠直接使用一個對象或數組
// 單獨聲明 const [height, setHeight] = useState(10) const [width, setWidth] = useState(20) const [left, setLeft] = useState(10) const [top, setTop] = useState(10) // 也能夠直接使用一個對象 const [state, setState] = useState({ height: 10, width: 20, left: 10, top: 10 })
在實際的使用中,按照邏輯將 state
分組是最佳實踐,避免了 state
對象過於臃腫也很好地將有關聯的 state
進行了分組維護。好比,上面聲明的幾個變量咱們能夠這樣進行分類
const [box, setBox] = useState({ height: 10, width: 20 }) const [position, setPosition] = useState({ left: 10, top: 10 })
useEffect(() => { effect return () => { cleanup }; }, [input])
特性:
useEffect Hook
看作 componentDidMount
,componentDidUpdate
和 componentWillUnmount
這三個函數的組合// 這個函數會在首次加載、state更新以及組件卸載的時候執行 useEffect(() => { console.log('方法執行了') return () => { console.log('解綁了') } })
componentDidMount
或 componentDidUpdate
不一樣,使用 useEffect
調度的 effect
不會阻塞瀏覽器更新屏幕,也就是說它是異步的effect
用來分離不一樣的邏輯(好比按照不一樣的用途),也就是說咱們能夠添加多個 effect
// 只有在 count 變化的時候,函數纔會執行 useEffect(() => { console.log('方法執行了') return () => { console.log('解綁了') } }, [count]) // 只在首次加載和卸載的時候執行 useEffect(() => { console.log('方法執行了') return () => { console.log('解綁了') } }, [])
effect
中用到的組件內的值effect
,那麼可使用一個可變的 ref
手動存儲一個 boolean
值來判斷effect
拿到的老是定義它的那次渲染中的 props
和 state
推薦閱讀 useEffect 完整指南 以及 如何在Effect中發送請求
const value = useContext(MyContext)
若是對於 context
並非十分熟悉,能夠先點擊 這裏,瞭解 context
的內容
特性:
context
對象(React.createContext
的返回值)並返回該 context
的當前值useContext
的參數必須是 context
對象自己context
值由上層組件中距離當前組件最近的 <MyContext.Provider>
的 value prop
決定useContext
的組件總會在 context
值變化時從新渲染// 官方文檔的案例,省去中間組件 const themes = { light: { foreground: "#000000", background: "#eeeeee" }, dark: { foreground: "#ffffff", background: "#222222" } } const ThemeContext = React.createContext(themes.light); function ThemedButton() { const theme = useContext(ThemeContext); return ( <button style={{ background: theme.background, color: theme.foreground }}> I am styled by theme context! </button> ) }
useState
的替代方案,若是熟悉 Redux
,那麼理解 Reducer
就很容易了
(state, action) => newState
的 reducer
,並返回當前的 state
以及與其配套的 dispatch
方法const initialState = {count: 0}; // action 用來表示觸發的行爲 function reducer(state, action) { switch (action.type) { case 'increment': return {count: state.count + 1}; case 'decrement': return {count: state.count - 1}; default: throw new Error(); } } function Counter() { const [state, dispatch] = useReducer(reducer, initialState); return ( <> Count: {state.count} <button onClick={() => dispatch({type: 'decrement'})}>-</button> <button onClick={() => dispatch({type: 'increment'})}>+</button> </> ); }
reducer
本質是一個純函數,每次只返回一個值,那個值能夠是數字,字符串,對象,數組或者對象,可是它老是一個值React
會確保 dispatch
函數的標識是穩定的,而且不會在組件從新渲染時改變useReducer
還能給那些會觸發深更新的組件作性能優化,由於能夠向子組件傳遞 dispatch
而不是回調函數reducer
更適合去處理比較複雜的 state
,來維護組件的狀態上面示例是一種基礎初始化 state
的方式,咱們也能夠選擇 惰性初始化
的方式
// init 是一個函數,返回值就是 state const [state, dispatch] = useReducer(reducer, initialArg, init)
若是使用這種方式初始化,state
的值就是 init(initialArg)
const refContainer = useRef(initialValue)
useRef
返回一個可變的 ref
對象,其 .current
屬性被初始化爲傳入的參數(initialValue
)。ref
對象在組件的整個生命週期內保持不變,能夠很方便地保存任何可變值.current
屬性不會引起組件從新渲染useRef()
建立的是一個普通的 Javascript
對象,而且每次渲染返回的都是同一個對象在理解 useRef
以前,咱們必定要清楚的是對於函數組件而言,每一次狀態的改變都是會從新觸發 render
。也就是說,咱們在組件狀態變化的時候拿到的值已是一個全新的數據,只是 react
幫咱們記住了以前的數據
利用 ref
對象的這個特性,咱們能夠實現:
effect
props
或 state
const memoizedCallback = useCallback( () => { doSomething(a, b); }, [a, b], )
函數組件的每一次調用都會執行內部的全部邏輯,帶來較大的性能損耗,因此 useCallback
出現了,它的做用就是解決性能問題。須要使用到緩存函數的地方,都是 useCallback
的應用場景
最多見的場景就是父組件傳遞給子組件的函數,props
中的某個依賴項不發生變化的狀況下,使用 useCallback
使子組件沒必要執行更新
將內聯函數和依賴項數組做爲參數傳入 useCallback
,該回調函數僅在某個依賴項改變時纔會更新,從而實現性能優化
useCallback
在每次渲染是都會執行;若是是一個空數組,那麼就只會在首次渲染的時候計算一次const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b])
與 useCallback
同樣,做爲性能優化的方式存在。與 useCallback
不一樣的是:useMemo
返回的是一個緩存的值
useMemo
在每次渲染時都會計算新的值,若是是一個空數組,那麼就只會在首次渲染的時候計算一次經過自定義 Hook,能夠將組件邏輯提取到可重用的函數中
在 hook
以前,咱們通常會使用 render props
和 高階函數來共享組件之間的狀態邏輯
如今,咱們可使用自定義 Hook
的方式來實現一樣的功能,並且可使邏輯條理更加清晰
Hook
是一個函數,其名稱以 use
開頭,函數內部能夠調用其餘的 Hook
Hook
是一種重用狀態邏輯的機制,並不會共享數據function useFriendStatus(friendID) { const [isOnline, setIsOnline] = useState(null); // ... return isOnline; }
以上主要介紹了 Hook
的一些重要特性以及常常會使用到的 Hook
,文章大部份內容以及示例都來自官網,而後就是本身整理總結的一點東西,知識點的整合
本文全部的示例,均可以在 這裏 找到
感興趣的小夥伴能夠 點擊這裏 ,也能夠掃描下方二維碼關注個人微信公衆號,查看更多前端小片斷,歡迎 star
關注