React Hooks系列之useRef

一糊识、useRef 是什么?

const myRef = useRef(initialValue);

  • useRef 返回一個(gè)可變的 ref 對(duì)象滨嘱,且只有一個(gè)current屬性射沟,初始值為傳入的參數(shù)( initialValue );
  • 返回的 ref 對(duì)象在組件的整個(gè)生命周期內(nèi)保持不變恨憎;
  • 當(dāng)更新 current 值時(shí)并不會(huì) re-render 蕊退,而 useState 更新值時(shí)會(huì)觸發(fā)頁面渲染;
  • 更新 useRef 是 side effect (副作用)憔恳,所以一般寫在 useEffect 或 event handler 里;
  • useRef 類似于類組件的 this瓤荔。

二、useRef 可以解決什么問題钥组?

1茉贡、使用useRef來獲取上一次的值
function usePrevious(value) {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  });
  return ref.current;
}

這個(gè)函數(shù)再渲染過程中總是返回上一次的值,因?yàn)?ref.current 變化不會(huì)觸發(fā)組件的重新渲染者铜,所以需要等到下次的渲染才能顯示到頁面上腔丧。

2、使用useRef來保存不需要變化的值

因?yàn)閡seRef的返回值在組件的每次redner之后都是同一個(gè)作烟,所以它可以用來保存一些在組件整個(gè)生命周期都不需要變化的值愉粤。最常見的就是定時(shí)器的清除場(chǎng)景。
(1)以前用全局變量設(shè)置定時(shí)器

const App = () => {
  let timer;
  useEffect(() => {
    timer = setInterval(() => {
      console.log('觸發(fā)了');
    }, 1000);
  },[]);
  const clearTimer = () => {
    clearInterval(timer);
  }
  return (
    <>
      <Button onClick={clearTimer}>停止</Button>
    </>)
}

上面的寫法存在一個(gè)問題拿撩,如果這個(gè)App組件里有state變化或者他的父組件重新render等原因?qū)е逻@個(gè)App組件重新render的時(shí)候衣厘,我們會(huì)發(fā)現(xiàn),點(diǎn)擊停止按鈕压恒,定時(shí)器依然會(huì)不斷的在控制臺(tái)打印影暴,定時(shí)器清除事件無效了。

因?yàn)榻M件重新渲染之后探赫,這里的timer以及clearTimer 方法都會(huì)重新創(chuàng)建型宙,timer已經(jīng)不是定時(shí)器的變量了。

(2)使用useRef定義定時(shí)器

const App = () => {
  const timer = useRef();
  useEffect(() => {
    timer.current = setInterval(() => {
      console.log('觸發(fā)了');
    }, 1000);
  },[]);
  const clearTimer = () => {
    clearInterval(timer.current);
  }
  return (
    <>
      <Button onClick={clearTimer}>停止</Button>
    </>)
}

(3) 實(shí)現(xiàn)一個(gè)深度依賴對(duì)比的 useDeepEffect
普通的useEffect只是一個(gè)淺比較的方法伦吠,如果我們依賴的state是一個(gè)對(duì)象妆兑,組件重新渲染,這個(gè)state對(duì)象的值沒變毛仪,但是內(nèi)存引用地址變化了搁嗓,一樣會(huì)觸發(fā)useEffect的重新渲染。

const createObj = () => ({
    name: 'zouwowo'
});
useEffect(() => {
  // 這個(gè)方法會(huì)無限循環(huán)
}, [createObj()]);

使用 useRef 實(shí)現(xiàn)深度依賴比較

import equal from 'fast-deep-equal';
export useDeepEffect = (callback, deps) => {
  const emitEffect = useRef(0);
  const prevDeps = useRef(deps);
  if (!equal(prevDeps.current, deps)) {
    // 當(dāng)深比較不相等的時(shí)候箱靴,修改emitEffect.current的值腺逛,觸發(fā)下面的useEffect更新
    emitEffect.current++;
  }
  prevDeps.current = deps;
  return useEffect(callback, [emitEffect.current]);
}

(4)小結(jié)

  • useRef 是定義在實(shí)例基礎(chǔ)上的,如果代碼中有多個(gè)相同的組件衡怀,每個(gè)組件的 ref 只跟組件本身有關(guān)棍矛,跟其他組件的 ref 沒有關(guān)系。
  • 組件前定義的 global 變量狈癞,是屬于全局的茄靠。如果代碼中有多個(gè)相同的組件,那這個(gè) global 變量在全局是同一個(gè)蝶桶,他們會(huì)互相影響慨绳。
  • 組件重新渲染之后,全局變量會(huì)被重新創(chuàng)建真竖,ref 則不會(huì)被刷新脐雪。
3、實(shí)現(xiàn)父組件獲取子組件的屬性和方法
import React, {MutableRefObject, useState, useEffect, useRef, useCallback} from 'react'
interface IProps {
    //prettier-ignore
    label: string,
    cRef: MutableRefObject<any>
}
const ChildInput: React.FC<IProps> = (props) => {
    const { label, cRef } = props
    const [value, setValue] = useState('')
    const handleChange = (e: any) => {
        const value = e.target.value
        setValue(value)
    }
    const getValue = useCallback(() => {
        return value
    }, [value])
    useEffect(() => {
        if (cRef && cRef.current) {
            cRef.current.getValue = getValue
        }
    }, [getValue])
    return (
        <div>
            <span>{label}:</span>
            <input type="text" value={value} onChange={handleChange} />
        </div>
    )
}
const ParentCom: React.FC = (props: any) => {
    const childRef: MutableRefObject<any> = useRef({})
    const handleFocus = () => {
        const node = childRef.current
        alert(node.getValue())
    }
    return (
        <div>
            <ChildInput label={'名稱'} cRef={childRef} />
            <button onClick={handleFocus}>focus</button>
        </div>
    )
}
export default ParentCom

父組件按鈕點(diǎn)擊時(shí)恢共,通過調(diào)用getValue战秋,獲取到子組件input里的value值。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末讨韭,一起剝皮案震驚了整個(gè)濱河市脂信,隨后出現(xiàn)的幾起案子癣蟋,更是在濱河造成了極大的恐慌,老刑警劉巖狰闪,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件疯搅,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡埋泵,警方通過查閱死者的電腦和手機(jī)幔欧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來丽声,“玉大人礁蔗,你說我怎么就攤上這事⊙闵纾” “怎么了浴井?”我有些...
    開封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)歧胁。 經(jīng)常有香客問我滋饲,道長(zhǎng),這世上最難降的妖魔是什么喊巍? 我笑而不...
    開封第一講書人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任屠缭,我火速辦了婚禮,結(jié)果婚禮上崭参,老公的妹妹穿的比我還像新娘呵曹。我一直安慰自己,他們只是感情好何暮,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開白布奄喂。 她就那樣靜靜地躺著,像睡著了一般海洼。 火紅的嫁衣襯著肌膚如雪跨新。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,007評(píng)論 1 284
  • 那天坏逢,我揣著相機(jī)與錄音域帐,去河邊找鬼。 笑死是整,一個(gè)胖子當(dāng)著我的面吹牛肖揣,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播浮入,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼龙优,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了事秀?” 一聲冷哼從身側(cè)響起彤断,我...
    開封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤野舶,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后瓦糟,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體筒愚,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年菩浙,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片句伶。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡劲蜻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出考余,到底是詐尸還是另有隱情先嬉,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布楚堤,位于F島的核電站疫蔓,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏身冬。R本人自食惡果不足惜衅胀,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望酥筝。 院中可真熱鬧滚躯,春花似錦、人聲如沸嘿歌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽宙帝。三九已至丧凤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間步脓,已是汗流浹背愿待。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留沪编,地道東北人呼盆。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像蚁廓,于是被迫代替她去往敵國和親访圃。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 前言 本文全面介紹了React Hooks的所有API概念相嵌、用法腿时、豐富的demo以及部分底層原理况脆。 實(shí)際上,Rea...
    南宮__閱讀 3,560評(píng)論 0 6
  • 1.React Hooks 介紹 React Hooks 是?來做什么的 對(duì)函數(shù)型組件進(jìn)?增強(qiáng), 讓函數(shù)型組件可以...
    JackoLam閱讀 308評(píng)論 0 0
  • 前言 最近的換寫React項(xiàng)目了批糟,好久沒有寫React格了,還動(dòng)不動(dòng)就想class??,現(xiàn)在跟上時(shí)代徽鼎,重新學(xué)習(xí)React...
    alex夏夜閱讀 1,954評(píng)論 1 3
  • 1.useState 使用單個(gè) state 變量還是多個(gè) state 變量useState 的出現(xiàn)盛末,讓我們可以使用...
    MelousJ閱讀 549評(píng)論 0 0
  • React16.8 發(fā)布已經(jīng)很長(zhǎng)世間, 這段時(shí)間項(xiàng)目不忙, 正好準(zhǔn)備使用 React Hooks 進(jìn)行重構(gòu)升級(jí)。R...
    ZiTong閱讀 196評(píng)論 0 0