想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等着你!html
類組件中使用 Ref 通常有:前端
上述在函數組件中沒有辦法使用它們,取而代之的是 useRef
Hooks。react
useRef
主要有兩個使用場景:git
你們可能會想到 state 也可跨越渲染週期保存,可是 state
的賦值會觸發重渲染,可是 ref
不會,從這點看 ref 更像是類屬性中的普通成員。github
粟例說明一下:獲取子組件或者 DOM 節點的句柄segmentfault
function TextInputWithFocusButton() { const inputEl = useRef(null); const onButtonClick = () => { // `current` 指向已掛載到 DOM 上的文本輸入元素 inputEl.current.focus(); }; return ( <> <input ref={inputEl} type="text" /> <button onClick={onButtonClick}>Focus the input</button> </> ); }
本質上,useRef
就像是能夠在其 .current
屬性中保存一個可變值的「盒子」。數組
粟例說明一下:渲染週期之間的共享數據的存儲函數
function App (props) { const [count, setCount] = useState(0); let it useEffect(() => { it = setInterval(() => { setCount(count => count + 1) }, 1000) } , []) useEffect(() => { if (count >= 5) { clearInterval(it) } }) return ( <div style={{padding:'100px'}}> <h1>{count}</h1> </div> ) }
上述使用 useEffect
聲明兩個反作用,第一個每隔一秒對 count
加 1,由於只需執行一次,因此每二個參爲空數組。第二個 useEffect
判斷 count
大於等於時,中止對 count
的操做。學習
運行結果:優化
顯示當 count
爲 5
的時候並無中止,這是爲何呢?
由於在 clearInterval
, it
這個變量已經不是 setInterval
賦值時的那個了,每次 App 重渲染都會重置它。這時候就可使用 useRef
來解決這個問題。
function App (props) { const [count, setCount] = useState(0); const it = useRef(null) useEffect(() => { it.current = setInterval(() => { setCount(count => count + 1) }, 1000) } , []) useEffect(() => { if (count >= 5) { clearInterval(it.current) } }) return ( ... ) }
使用 useRef
來建立一個 it
, 當 setInterval
返回的結果賦值給 it
的 current
屬性。
運行結果:
你應該熟悉 ref
這一種訪問 DOM 的主要方式。若是你將 ref
對象以 <div ref={myRef} />
形式傳入組件,則不管該節點如何改變,React 都會將 ref
對象的 .current
屬性設置爲相應的 DOM 節點。
然而,useRef()
比 ref
屬性更有用。它能夠很方便地保存任何可變值,其相似於在 class 中使用實例字段的方式。
這是由於它建立的是一個普通 Javascript 對象。而 useRef()
和自建一個 {current: ...}
對象的惟一區別是,useRef
會在每次渲染時返回同一個 ref 對象。
請記住,當 ref 對象內容發生變化時,useRef 並不會通知你。變動 .current 屬性不會引起組件從新渲染。若是想要在 React 綁定或解綁 DOM 節點的 ref 時運行某些代碼,則須要使用回調 ref 來實現。
前面三篇,咱們講到優化類組件的三大問題:
this
問題對於組件的複用狀態沒怎麼說明,如今使用自定義 Hook 來講明一下。
首先咱們把上面的例子用到 count
的邏輯的用自定義 Hook 封裝起來:
function useCount(defaultCount) { const [count, setCount] = useState(defaultCount); const it = useRef() useEffect(() => { it.current = setInterval(() => { setCount(count => count + 1) }, 1000) } , []) useEffect(() => { if (count >= 5) { clearInterval(it.current) } }) return [count, setCount] } function App (props) { const [count, setCount] = useCount(0); return ( <div style={{padding: '100px'}}> <h1>{count}</h1> </div> ) }
運行效果:
能夠看出運行效果跟上面是同樣的。
定義 Hook 是一個函數,其名稱以 「use」 開頭,函數內部能夠調用其餘的 Hook。咱們在函數自定義寫法上彷佛和編寫函數組件沒有區別,確實自定義組件與函數組件的最大區別就是輸入與輸出的區別。
再來一個特別的 Hook 加深一下映像。在上述代碼不變的條件下,咱們在加一個自定義 Hook 內容以下:
function useCounter(count) { return ( <h1>{count}</h1> ) }
在 App 組件調用:
function App (props) { const [count, setCount] = useCount(0); const Counter = useCounter(count) return ( <div style={{padding: '100px'}}> {Counter} </div> ) }
運行效果:
咱們自定義 useCounter
Hook返回的是一個 JSX,運行效果是同樣的,因此 Hook 是能夠返回 JSX 來參與渲染的,更說明 Hook 與函數組件的類似性。
不要在循環,條件或嵌套中調用 Hook,確保老是在你的 React 函數的最頂層調用他們。遵照這條規則,你就能確保 Hook 在每一次渲染中都按照一樣的順序被調用。這上 React 可以在屢次的 useState 和 useEffect 調用之間保持 hook 狀態的正確。
不要在普通的 JavaScript 函數中調用 Hook, 你能夠:
如下主要說明幾個典型的問題,固然這在官網上都有說明。
constructor
:函數組件不須要構造函數。你能夠經過調用 useState
來初始化 state
。若是計算的代價比較昂貴,你能夠傳一個函數給 useState
。getDerivedStateFromProps
:改成 在渲染時 安排一次更新render
:這是函數組件體自己。componentDidMount
, componentDidUpdate
, componentWillUnmount
:useEffect Hook 能夠表達全部這些(包括 不那麼 常見 的場景)的組合。componentDidCatch
and getDerivedStateFromError
:目前尚未這些方法的 Hook 等價寫法,但很快會加上。
若是先後兩次的值相同,useState 和 useReducer Hook 都會放棄更新。原地修改 state 並調用 setState 不會引發從新渲染。
一般,你不該該在 React 中修改本地 state。然而,做爲一條出路,你能夠用一個增加的計數器來在 state 沒變的時候依然強制一次從新渲染:
const [ignored, forceUpdate] = useReducer(x => x + 1, 0); function handleClick() { forceUpdate(); }
可能的話儘可能避免這種模式。
乾貨系列文章彙總以下,以爲不錯點個Star,歡迎 加羣 互相學習。
https://github.com/qq44924588...
我是小智,公衆號「大遷世界」做者,對前端技術保持學習愛好者。我會常常分享本身所學所看的乾貨,在進階的路上,共勉!
關注公衆號,後臺回覆福利,便可看到福利,你懂的。