React16.8.0+版本才支持Hooks;徹底可選,能夠只在部分函數組件裏面應用Hooks,不必徹底應用Hooks到整個項目;徹底向後兼容,沒有重大改變;尚無計 劃移除Class組件,下文會有過渡策略;Hooks沒有新概念,也沒有修改舊理念,只是一種更加簡單直接的API,來對既有的props,state,context,refs, lifeCycle作強有力的組合;Hooks能夠解決許多表面看似不相關的問題。html
React沒有提供一個將可複用行爲(比方說connect到store)粘貼到組件的方式。render props和higher-order components能夠解決這類問題。可是這些 模式須要對相關組件進行重構。有可能會略顯笨重,較複雜的話很難繼續改造。在React DevTools裏面會發現組件的‘wrapper hell‘,有providers、 consumers、higher-order components、render props以及其餘抽象層。node
有了Hooks的話,咱們能夠從一個組件當中抽取出stateFul logic,單獨測試並複用起來。這些都是Hooks定製化的基石。react
咱們發現一些組件一開始很簡單,可是慢慢變得不易於維護,處處瀰漫着stateFul logic、反作用。每一個生命週期鉤子方法常常混合着許多不相關邏輯。例如, 組件在componentDidMount和componentDidUpdate中請求數據,可是componentDidMount方法也有可能包含註冊事件監聽,在componentWillUnmount中 取消事件監聽。一同變化的相關代碼被拆分開來了,徹底不相關的代碼卻在一個方法裏結合起來了。這樣很容易引入bug。git
就像Svelte、Angular、Glimmer那樣,組件預編譯會在將來釋放巨大潛力。特別是不侷限於模板,最近React團隊在使用Prepack探索component folding:github
function Foo (props) {
if (props.data.type === 'img') {
return <img src={props.data.src} className={props.className} alt={props.alt} />
}
return <span>{props.data.type}</span>
}
Foo.defaultProps = {
alt: 'An image of Foo'
}
var CSSClasses = {
bar: 'bar'
}
module.exports = CSSClasses;
var Foo = require('Foo')
var Classes = require('Classes')
function Bar (props) {
return <Foo data={{ type: 'img', src: props.src }} className={Classes.bar} />
}
function Bar_optimized (props) {
return <img src={props.src} className="bar" alt="An image of Foo." />
}
// All above is called `Dead-code Elimination`
複製代碼
發現class組件會有潛在模式,使得component folding作出的優化回退到一個更慢的結果。classes也存在諸如這些問題:壓縮不足,熱加載分離成片狀,不可靠。 咱們想要推出一款API使得代碼依然保持住component folding作出的優化。 是他是他就是他了,Hooks讓你可以不用Classes卻能使用上已有的React特性。React 組件老是貼近於函數。Hooks擁抱函數,可是不會犧牲React的精髓,而且 不要求你掌握複雜的函數式、響應式編程技巧。web
Hooks和現有代碼是並行關係,不提倡把現有class組件改寫爲hooks,特別是複雜的大組件,可是新組件能夠採用Hooks來寫^_^npm
import React, { useState } from 'react'
function Example () {
const [count, setCount] = useState(0)
return (
<div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}>Click me</button> </div>
)
}
// equivalent to
class Example extend React.Component {
constructor (props) {
super(props)
this.state = {
count: 0
}
}
render () {
return (
<div> <p>You clicked {count} times</p> <button onClick={() => this.setState({ count: this.state.count + 1 })}>Click me</button> </div>
)
}
}
複製代碼
這時候咱們再來解釋一下React Hooks:一個Hook是一個可以hook into
React特性的特殊函數。useState
是一個增長React state到函數組件的 Hook。編程
執行組件裏的反作用,和class組件的生命週期方法類似。useEffect
Hook是 componentDidMount, componentDidUpdate, componentWillUnmount
的結合體json
import React, { useState, useEffect } from 'react'
function Example () {
const [count, setCount] = useState(0)
// Similar to componentDidMount and componentDidUpdate
useEffect(() => { // this arrow method is called the effect method, you can also name it rather than arrow function
// using arrow function, if there's lot code, we should add remark, on the other side, we can use multiple useEffect
// with named-effect-function if you like
// Update the document title using the browser API
document.title = `You clicked ${count} times`
})
return (
<div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}>Click me</button> </div>
)
}
// equivalent to
class Example extend React.Component {
constructor (props) {
super(props)
this.state = {
count: 0
}
}
componentDidMount () {
document.title = `You clicked ${this.state.count} times`
}
// duplicate code in another lifeCycle method
componentDidUpdate () {
document.title = `You clicked ${this.state.count} times`
}
render () {
return (
<div> <p>You clicked {count} times</p> <button onClick={() => this.setState({ count: this.state.count + 1 })}>Click me</button> </div>
)
}
}
複製代碼
React組件有兩種反作用:一種不要求cleanup,另外一種要求cleanup。redux
有時候,咱們想要在React更新DOM以後運行一些代碼。網絡請求、DOM手動操做、日誌、以及其餘的命令式API是常見的不要求cleanup的effects。咱們說咱們運行完後就馬上忘記這塊 代碼。 在class組件裏,render
方法不會帶來反作用,咱們會在componentDidMount, componentDidUpdate
當中放入反作用。能夠看到上面的代碼在兩個生命 週期方法裏重複了,由於咱們想要的效果是無論組件是掛載完仍是更新完都去執行一樣的反作用。也就是說咱們想要每次渲染後都執行一樣的某個邏輯,可是 React沒有這樣的方法,咱們能夠抽成一個獨立方法可是仍然須要在兩個生命週期方法裏分別調用一次 useEffect能夠讀取函數組件內的state、props這一能力依賴於函數做用域。Hooks擁抱JavaScript閉包因此避免引入React特定API,由於閉包已經作到了, React Hooks原理能夠參考github源碼,之後我會抽時間整理成一篇博客。 若是你簡單的理解每一個useEffect都是在每次render以後執行的話,那你可能還不知道useEffect的第二個參數(影響因子數組)。 有經驗的開發者可能注意到useEffect的第一個方法參數每次渲染後都會不同。沒錯,這樣咱們就能夠在effect
內部讀取到最新的count
數據,每次渲染後 ,都會有一個不一樣的新effect方法替換以前的舊effect方法。某種程度上,這使得effects表現的更像render結果的一部分,每一個effect屬於一個render。
和componentDidMount, componentDidUpdate
不一樣的是,effects不會阻止瀏覽器更新渲染幀。webApp響應性會更好。大部分effects沒必要同步發生。 在一些不常見的場景好比計算佈局的時候,須要同步的effects。能夠採用區別於useEffect
的useLayoutEffect
API。
像事件的添加與銷燬、subscribe && unsubscribe等等。
不要在循環、條件或者嵌套語句中調用Hooks。
咱們要在React函數組件內部最外層直接調用Hooks,這樣,Hooks能夠在每一次組件渲染的時候保持順序一致,React也能夠正確保存屢次調用useState useEffect
之間的Hooks狀態。能夠在React函數組件、custom Hooks內部調用Hooks,可是不要在正常的JavaScript函數內部調用Hooks。這樣能夠確保組件內部的 全部stateFul logic
可讀性強。若是寫JavaScript而不是TypeScript的話能夠install eslint-plugin-react-hooks
:
// Your eslint configuration
{
"plugins": [
// ...
"react-hooks"
],
"rules": {
// ...
"react-hooks/rules-of-hooks": "error", // Checks rules of hooks
"react-hooks/exhaustive-deps": "warn" // Checks effect dependencies
}
}
複製代碼
如今咱們來解釋下爲何須要把Hooks調用放在函數組件內部最外層:
function Form () {
// 1. Use the name state variable
const [ name, setName ] = useState('Mary')
useEffect(function persistForm () {
localStorage.setItem('formData', name)
})
const [ surname, setSurname ] = useState('Poppins')
useEffect(function updateTitle () {
document.title = `${name} ${surname}`
})
}
// React怎麼就知道哪一個state是哪一個useState調用出來的呢,其實依賴於Hooks的調用順序。咱們的例子能夠起做用的緣由在於每次渲染時Hooks的調用順序
// 保持一致!
// First Render
useState('Mary') // 1. Initialize the name state variable with 'Mary'
useEffect(persistForm) // 2. Add an effect for persisting the form
useState('Poppins') // 3. Initialize the surname state
// Second Render
useState('Mary') // 1. Read the name state variable (argument is ignored)
useEffect(persistForm) // 2. Replace the effect for persisting the form
useState('Poppins') // 3. Read the surname state variable(argument is ignored)
useEffect(updateTitle) // 4. Replace the effect for updating the title
複製代碼
只要每次渲染的Hooks調用順序保持一致,React就能夠把一些本地state數據和每次調用關聯起來。可是把一個Hook調用放入一個condition的話:
if (name !== '') {
useEffect(function persistForm () {
localStorage.setItem('formData', name)
})
}
複製代碼
第一次渲染時name !== ''
條件是true
,執行了這條Hook,可是,下次渲染時用戶有可能清除了表單,條件值爲false
,跳過了這條Hook,Hooks調用順序 改變了:
useState('Mary') // 1. Read the name state variable (argument is ignored)
// useEffect(persistForm) // This Hook was skipped!
useState('Poppins') // 2(but was 3). Failed to read the surname state variable
useEffect(updateTitle) // 3(but was 4). Failed to replace
複製代碼
React在第二次useState
調用時並不知道要return什麼。React期待組件內第二個Hook調用是persistForm
effect,就像上一次render時那樣,然而並 不是。咱們跳過的Hook後面的每一個Hook都會遷移一位,引來bug。 若是咱們想條件性地執行一個effect,咱們要把條件放到Hook內部:
useEffect(function persistForm () {
if (name !== '') {
localStorage.setItem('formData', name)
}
})
複製代碼
構建本身的Hooks,使得分離組件邏輯到可複用地函數組件去。 以前咱們學習Effect Hook時,看到用一條信息代表朋友是否在線的聊天應用:
import React, { useState, useEffect } from 'react'
function FriendStatus (props) {
const [ isOnline, setIsOnline ] = useState(null)
useEffect(() => {
function handleStatusChange (status) {
setIsOnline(status.isOnline)
}
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange)
return () => {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange)
}
})
if (isOnline === null) return 'Loading...'
return `O${isOnline ? 'n' : 'ff'}line`
}
複製代碼
如今應用要增長聯繫人列表,並且須要展現綠色在線狀態的許多姓名,咱們能夠吧類似邏輯複製到咱們的FriendListItem
組件可是不夠理想:
import React, { useState, useEffect } from 'react'
function FriendListItem(props) {
const [isOnline, setIsOnline] = useState(null)
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline)
}
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange)
return () => {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange)
}
})
return (
<li style={{ color: isOnline ? 'green' : 'black' }}> {props.friend.name} </li>
)
}
複製代碼
換句話說,如何複用FriendStatus FriendListItem
的邏輯呢。之前針對class組件,咱們有render props, higher-order components
兩個手段來複用組件內部 邏輯。對於Hooks的話,又該如何在不增長組件樹層級的狀況下解決一樣的問題呢。方案就是:
在JavaScript函數間複用邏輯的辦法是剝離出另外一個函數,函數組件和Hooks都是函數,因此同理嘍! 一個自定義Hook是一個以「use「打頭的JavaScript函數,它調用了其餘Hooks:
import React, { useState, useEffect } from 'react'
function useFriendStatus (friendID) {
const [ isOnline, setIsOnline ] = useState(null)
useEffect(() => {
function handleStatusChange (status) {
setIsOnline(status.isOnline)
}
ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange)
return () => {
ChatAPI.unsubscribeToFriendStatus(friendID, handleStatusChange)
}
})
return isOnline
}
複製代碼
和React 組件不同的是,一個自定義Hook不用特定簽名。咱們自行決定參數,返回值,和正常函數同樣,惟一不一樣的就是以use
開頭,這樣就能方便應用rules of Hooks
。 如今看看如何使用自定義Hook:
function FriendStatus (props) {
const isOnline = useFiendStatus(props.friend.id)
if (isOnline === null) return 'Loading'
return `O${isOnline ? 'n' : 'ff'}line`
}
function FriendListItem (props) {
const isOnline = useFiendStatus(props.friend.id)
return (
<li style={{ color: isOnline ? 'green' : 'black' }}> {prop.friend.name} </li>
)
}
複製代碼
咱們約定了自定義Hooks必須yiuse
開頭,很是重要,不然咱們沒法檢測Hooks規則,由於沒法判斷一個函數組件內部是否包含Hooks。 使用相同Hook的兩個函數組件共享狀態嗎?No,自定義Hooks時複用組件本地邏輯的機制,好比發起訂閱、記住當前值,可是每次使用一個自定義Hook的時候,它的所 有state和effects都是獨立的。 一個自定義的Hook如何獲取獨立的state?一個Hook的每次調用都有獨立的狀態。由於咱們是直接調用了useFriendStatus
,React認爲咱們的組件僅僅調用了 useState useEffect
。
自定義Hooks提供了React組件史無前例的複用邏輯地靈活性。咱們能夠處理表單、動畫製做、聲明式訂閱、定時器、等等。 不要過早增長抽象。既然函數組件能夠作不少,那麼一不當心就會增長函數長度,這很正常,可是不用以爲馬上寫成Hooks。
若是更新邏輯複雜或者數據須要聚合的話(比方說表單),能夠考慮用useReducer
代替useState
,也用到了redux的思想,不亦樂乎。
const [ state, setState ] = useState(initialState)
複製代碼
首次渲染時,返回的state就是initialState
。setState
是用來更新state的方法,參數是新的state值,enqueue進組件從新渲染的隊列。
若是新state時前一個state計算出來的,能夠給 setState
傳遞一個函數,該函數接收前一個state做爲參數,而後return新的state:
function Counter (initialCount) {
const [ count, setCount ] = useState(initialCount)
return (
<> Count: {count} <button onClick={() => setCount(initialCount)}>Reset</button> <button onClick={() => setCount(prevCount => prevCount + 1)}>+</button> <button onClick={() => setCount(prevCount => prevCount - 1)}>-</button> </> ) } 複製代碼
和class組件 setState
不一樣的是,useState
不會自動合併更新對象。可是咱們能夠採用ES6擴展符+函數更新形式來作:
setState(prevState => ({ ...prevState, ...updatedValues }))
複製代碼
另外就是能夠採用useReducer
,更適合包含多個子值的state對象。
若是初始值initialState
是複雜計算的結果呢:
const [ state, setState ] = useState(() => {
const initialState = someExpensiveComputation(props)
return initialState
})
複製代碼
React採用Object.is
來比較先後state,以此來決定是否更新children或者觸發effects。
React有可能在bail out(先後state一致,不會從新渲染)以前仍然再次渲染特定組件。咱們沒必要在意那麼多,由於React不會進入到更深層級。 固然若是你在渲染時須要作複雜的計算,能夠用useMemo
來優化。
useEffect(didUpdate)
didUpdate
是包含聲明式、或者反作用的方法,好比訂閱、訂閱、定時器、日誌、等等反作用代碼容許直接置於React函數組件內部(render phase
),要 寫反作用代碼的話就用useEffect
吧。
清除反作用
反作用常常搞出一些須要在組件卸載以前清除的資源,好比說訂閱、定時器ID。這時候咱們可讓useEffect
return一個清除器函數,來避免內存泄露:
useEffect(() => {
const subscription = props.source.subscribe()
return () => {
subscription.unsubscribe()
}
})
複製代碼
另外,前一個effect會在執行下一個effect以前被清除掉。咱們的例子中,每次更新時都會有一次新訂閱。那麼怎麼避免每次更新時觸發一次effect呢。
不像componentDidMount componentDidUpdate
,傳遞給useEffect
的方法會在layout、paint後觸發,在一次延遲事件中。這對於大多數像訂閱、事件 處理器這樣的反作用都比較合適,由於大多數都不會阻塞瀏覽器更新幀。
可是,不是全部的反作用都會被推遲。好比對於用戶可見的DOM修改必須在下一次重繪以前同步觸發,這樣用戶就不會感受到卡頓。對於這類effects,React提供 一個叫作useLayoutEffect
的Hook。和useEffect
一個樣子,只是觸發時機不一致。
儘管useEffect
被推遲到瀏覽器重繪以後,卻能在每次渲染以前觸發。React總會在一次更新以前把上一次渲染的effects清除掉。
有條件地觸發一次effect
拿上面的訂閱器例子來講,每次更新時,咱們其實能夠只在source改變時去從新訂閱:
// 給useEffect傳遞第二個數組參數,只有當數組裏面的變量變化時纔去觸發該effect
useEffect(() => {
const subscription = props.source.subscribe()
return () => {
subscription.unsubscribe()
}
}, [props.source])
複製代碼
須要注意的是,要確認數組元素是完備的,全部能決定該effect發生與否的變量都需列出。要否則有可能會錯誤地引用舊渲染中的值。
若是你想執行一次effect,而且也只清除一次(mount unmount
),那麼能夠傳遞空數組[]
做爲第二個參數。React知道此effect不依賴任何props、state 數據,因此不會從新執行。
咱們推薦使用eslint-plugin-react-hooks的時候使用exhaustive-deps
規則,依賴沒有正確指定時會有警告,並告知如何修復。
每個effect方法內部引用的值都應該在依賴列表中出現。不久的未來,一個高級編譯器可以自動構建該數組。
useContext
const value = useContext(MyContext) // Accepts a context object(the value returned from React.createContext)
複製代碼
一個調用useContext
的組件總會在context變更時從新渲染。若是從新渲染組件很耗性能,那麼請使用useMemo
若是你以前熟悉context API的話,應該懂得useContext(MyContext)
等同於類組件的static contextType = MyContext
或者<MyContext.Consumer>
useContext(MyContext)
只會讓你讀取context,而且訂閱它的變更。你仍然在組件樹中須要<MyContext.Provider>
,來爲此context提供值
下面的Hooks要麼是基礎hooks的變體,要麼是特定場合下的的需求。不用擔憂提早學習沒用的東西。
useReducer
const [state, dispatch] = useReducer(reducer, initialState)
// or
const [state, dispatch] = useReducer(reducer, initialArg, init) // 初始state會被設置成 init(initialArg)
// 你能夠把計算初始state的邏輯抽離到reducer以外,這樣也有利於初始化state的action操做:
function init (initialCount) {
return { count: initialCount }
}
function reducer (state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 }
case 'decrement':
return { count: state.count - 1 }
case 'reset':
return init(action.payload)
default:
throw new Error()
}
}
function Counter ({ initialCount }) {
const [ state, dispatch ] = useReducer(reducer, initialCount, init)
return (
<> Count: {state.count} <button onClick={() => dispatch({ type: 'reset', payload: initialCount })}> Reset </button> <button onClick={() => dispatch({ type: 'increment' })}>+</button> <button onClick={() => dispatch({ type: 'decrement' })}>-</button> </> ) } 複製代碼
useCallback
const memoizedCb = useCallback(
() => {
doSomething(a, b)
},
[ a, b ],
)
複製代碼
做用相似於shouldComponentUpdate
useCallback(fn, deps)
等同於useMemo(() => fn, deps)
useMemo
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [ a, b ])
複製代碼
useRef
const refContainer = useRef(initialVal)
複製代碼
useRef
返回一個可改變的ref對象,.current
屬性初始化成initialValue
參數。返回的對象會在組件的生命週期內始終存留。 好比說要命令式地訪問子組件:
function TextInputWithFocusButton () {
const inputEl = useRef(null)
const onBtnClick = () => {
// `current` 指向掛載了的輸入框元素
inputEl.current.focus()
}
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onBtnClick}>Focus the input</button>
</>
)
}
複製代碼
可是useRef()
比ref
屬性更有用。就像class實例屬性同樣方便。
useRef
不會在內容變更時通知你,改變.current
屬性不會引起從新渲染。若是你想要在React掛載或者卸載某個DOM節點的ref時執行某些代碼的話,採用 callback ref吧.
useImperativeHandle
useImperativeHandle(
ref,
() => {
handler
}, // createHandle
[input], // deps
)
複製代碼
useImperativeHandle
自定義了使用ref
時暴露給父組件的實例值。正常狀況下,使用refs的命令式代碼應該避免。userImperativeHandle
應該和 forwardRef
一塊兒使用。
function FancyInput (props, ref) {
const inputRef = useRef()
useImperatieHandle(ref, () => ({
focus: () => {
inputRef.current.focus()
},
}))
return <input ref={inputRef} ... /> } FancyInput = forwardRef(FancyInput) 複製代碼
一個渲染<FancyInput ref={FancyInputRef} />
的父組件,可以調用fancyInputRef.current.focus()
useLayoutEffect 形式相似useEffect
,可是在全部DOM操做以後馬上觸發。用它去從DOM中讀取layout而後從新渲染。
useLayoutEffect
和componentDidMount componentDidUpdate
觸發階段一致。咱們推薦儘可能多用useEffect
,只有遇到問題纔去嘗試useLayoutEffect
。
服務端渲染的話,useLayoutEffect useEffect
都是在JavaScript下載後纔去執行,因此React會對包含useLayoutEffect
的服務端渲染組件發出⚠️。 有兩個修復手段:把邏輯搬進useEffect
(若是第一次渲染沒有必要);推遲組件顯示到客戶端渲染(若是直到useLayoutEffect
執行後HTML才顯得完整)。
爲了從服務端渲染HTML中剔除須要layout effects的組件,採用條件渲染:showChild && <Child />
而且推遲顯示:useEffect(() => { setShowChild(true) }, [])
。這樣的話UI就不會有broken現象。
useDebugValue
useDebugValue(value)
複製代碼
用於在React開發者工具中顯示自定義hooks的標籤:
function useFriendStatus (friendID) {
const [ isOnline, setIsOnline ] = useState(null)
// ...
// Show a label in DevTools next to this Hook
// e.g. "FriendStatus: Online"
useDebugValue(isOnline ? 'Online' : 'Offline')
return isOnline
}
複製代碼
這裏有一篇Dan Abramov在medium上面發表的文章。
目標是儘快吧,可是getSnapshotBeforeUpdate componentDidCatch
這兩個鉤子暫時尚未覆蓋到,可是處於計劃當中。
常常吧,render props和高階組件都只渲染一個子組件。咱們把Hooks看做一個簡潔之法。可是render props、高階組件仍是有額外用武之地: 一個有renderItem
屬性的虛擬滾動條組件、包含特定DOM結構的虛擬容器組件。可是大多數狀況下,Hooks足夠有用,能夠減小組件樹深度。
不會。 不過在未來,這些庫的新版本有可能會有一些自定義Hooks:useRedux() useRouter()
這樣的,就用不上容器組件了。
基於函數,你說呢。比起HOC,TypeScript徹底擁抱React Hooks。
constructor
: 函數組件不須要構造器,能夠用useState初始化state。getDerivedStateFromProps
: 能夠嘗試在render時更新shouldComponentUpdate
: 用React.memo
來實現render
: 函數體自己componentDidMount, componentDidUpdate, componentWillUnmount
: useEffect
均可以作到componentDidCatch, getDerivedStateFromError
: 暫不支持,之後會增長相應Hook這裏有個codesandbox的Demo, 還有這篇文章講得很全。
useRef()
不只僅是DOM引用。ref
對象是一個帶有current
屬性的通用容器,他能夠被修改,容納任何值,就有一個類的實例屬性:
function Timer () {
const intervalRef = useRef()
useEffect(() => {
const id = setInterval(() => {
// ...
})
intervalRef.current = id
return () => {
clearInterval(intervalRef.current)
}
})
}
複製代碼
function Counter () {
const [ count, setCount ] = useState(0)
const prevCountRef = useRef()
useEffect(() => {
prevCountRef.current = count
})
const prevCount = prevCountRef.current
return <h1>Now: {count}, before: {prevCount}</h1>
}
複製代碼
爲了測量DOM節點的尺寸、大小。用callback ref吧:
function MeasureExample () {
const [ height, setHeight ] = useState(0)
const measuredRef = useCallback(node => {
if (node !== null) setHeight(node.getBoundingClientRect().height)
}, [])
return (
<> <h1 ref={measuredRef}>Hello, world</h1> <h2>The above header is {Math.round(height)}px tall</h2> </> ) } 複製代碼
上面例子中咱們爲何不用useRef
呢,由於一個ref對象不會在ref值變更的時候發出通知。採用回調ref能夠作到子組件也能夠顯示測量好的node節點。
另外還有許許多多的Hooks FAQ,你們能夠多看看React官網FAQ。
Hooks 相關的博客、資源我找了一些挺不錯的:
star數上千的github項目卻並很少,博客比較少; 我能找到比較好的資源有(大俠看到好的資源能夠留個言?):
總結一下,咱們應該花更多的精力多看官網對其原理機制、使用的闡述,還有多研究一下高級hooks、自定義hooks;能夠貢獻到github或者寫成博客,這樣hooks社區就會好不少, 另外有空能夠看看源碼。