最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

React新文檔切記不要濫用Ref

 更新時(shí)間:2022年07月08日 11:19:23   作者:魔術(shù)師卡頌  
這篇文章主要為大家介紹了React新文檔濫用Ref出現(xiàn)的問題詳解,以及如何正確的使用Ref,有需要的朋友可以借鑒參考下,希望能夠有所幫助

引言

React新文檔有個(gè)很有意思的細(xì)節(jié):useRef、useEffect這兩個(gè)API的介紹,在文檔中所在的章節(jié)叫Escape Hatches(逃生艙)。

顯然,正常航行時(shí)是不需要逃生艙的,只有在遇到危險(xiǎn)時(shí)會(huì)用到。

如果開發(fā)者過多依賴這兩個(gè)API,可能是誤用。

React新文檔:不要濫用effect哦中我們談到useEffect的正確使用場(chǎng)景。

今天,我們來(lái)聊聊Ref的使用場(chǎng)景。

為什么是逃生艙?

先思考一個(gè)問題:為什么ref、effect被歸類到逃生艙中?

這是因?yàn)槎卟僮鞯亩际敲撾xReact控制的因素。

effect中處理的是副作用。比如:在useEffect中修改了document.title。

document.title不屬于React中的狀態(tài),React無(wú)法感知他的變化,所以被歸類到effect中。

同樣,使DOM聚焦需要調(diào)用element.focus(),直接執(zhí)行DOM API也是不受React控制的。

雖然他們是脫離React控制的因素,但為了保證應(yīng)用的健壯,React也要盡可能防止他們失控。

失控的Ref

對(duì)于Ref,什么叫失控呢?

首先來(lái)看不失控的情況:

  • 執(zhí)行ref.currentfocusblur等方法
  • 執(zhí)行ref.current.scrollIntoView使element滾動(dòng)到視野內(nèi)
  • 執(zhí)行ref.current.getBoundingClientRect測(cè)量DOM尺寸

這些情況下,雖然我們操作了DOM,但涉及的都是React控制范圍外的因素,所以不算失控。

但是下面的情況:

  • 執(zhí)行ref.current.remove移除DOM
  • 執(zhí)行ref.current.appendChild插入子節(jié)點(diǎn)

同樣是操作DOM,但這些屬于React控制范圍內(nèi)的因素,通過ref執(zhí)行這些操作就屬于失控的情況。

舉個(gè)例子,下面是React文檔中的例子

按鈕1點(diǎn)擊后會(huì)插入/移除 P節(jié)點(diǎn),按鈕2點(diǎn)擊后會(huì)調(diào)用DOM API移除P節(jié)點(diǎn):

export default function Counter() {
  const [show, setShow] = useState(true);
  const ref = useRef(null);
  return (
    <div>
      <button
        onClick={() => {
          setShow(!show);
        }}>
        Toggle with setState
      </button>
      <button
        onClick={() => {
          ref.current.remove();
        }}>
        Remove from the DOM
      </button>
      {show && <p ref={ref}>Hello world</p>}
    </div>
  );
}

按鈕1通過React控制的方式移除P節(jié)點(diǎn)。

按鈕2直接操作DOM移除P節(jié)點(diǎn)。

如果這兩種移除P節(jié)點(diǎn)的方式混用,那么先點(diǎn)擊按鈕1再點(diǎn)擊按鈕2就會(huì)報(bào)錯(cuò):

這就是使用Ref操作DOM造成的失控情況導(dǎo)致的。

如何限制失控

現(xiàn)在問題來(lái)了,既然叫失控了,那就是React沒法控制的(React總不能限制開發(fā)者不能使用DOM API吧?),那如何限制失控呢?

React中,組件可以分為:

  • 高階組件
  • 低階組件

低階組件指那些基于DOM封裝的組件,比如下面的組件,直接基于input節(jié)點(diǎn)封裝:

function MyInput(props) {
  return <input {...props} />;
}

在低階組件中,是可以直接將ref指向DOM的,比如:

function MyInput(props) {
  const ref = useRef(null);
  return <input ref={ref} {...props} />;
}

高階組件指那些基于低階組件封裝的組件,比如下面的Form組件,基于Input組件封裝:

function Form() {
  return (
    <>
      <MyInput/>
    </>
  )
}

高階組件無(wú)法直接將ref指向DOM,這一限制就將ref失控的范圍控制在單個(gè)組件內(nèi),不會(huì)出現(xiàn)跨越組件的ref失控。

文檔中的示例為例,如果我們想在Form組件中點(diǎn)擊按鈕,操作input聚焦:

function MyInput(props) {
  return <input {...props} />;
}
function Form() {
  const inputRef = useRef(null);
  function handleClick() {
    inputRef.current.focus();
  }
  return (
    <>
      <MyInput ref={inputRef} />
      <button onClick={handleClick}>
        input聚焦
      </button>
    </>
  );
}

點(diǎn)擊后,會(huì)報(bào)錯(cuò):

這是因?yàn)樵?code>Form組件中向MyInput傳遞ref失敗了,inputRef.current并沒有指向input節(jié)點(diǎn)。

究其原因,就是上面說的為了將ref失控的范圍控制在單個(gè)組件內(nèi),React默認(rèn)情況下不支持跨組件傳遞ref。

人為取消限制

如果一定要取消這個(gè)限制,可以使用forwardRef API顯式傳遞ref

const MyInput = forwardRef((props, ref) => {
  return <input {...props} ref={ref} />;
});
function Form() {
  const inputRef = useRef(null);
  function handleClick() {
    inputRef.current.focus();
  }
  return (
    <>
      <MyInput ref={inputRef} />
      <button onClick={handleClick}>
        Focus the input
      </button>
    </>
  );
}

使用forwardRefforward在這里是傳遞的意思)后,就能跨組件傳遞ref。

在例子中,我們將inputRefForm跨組件傳遞到MyInput中,并與input產(chǎn)生關(guān)聯(lián)。

在實(shí)踐中,一些同學(xué)可能覺得forwardRef這一API有些多此一舉。

但從ref失控的角度看,forwardRef的意圖就很明顯了:既然開發(fā)者手動(dòng)調(diào)用forwardRef破除防止ref失控的限制,那他應(yīng)該知道自己在做什么,也應(yīng)該自己承擔(dān)相應(yīng)的風(fēng)險(xiǎn)。

同時(shí),有了forwardRef的存在,發(fā)生ref相關(guān)錯(cuò)誤后也更容易定位錯(cuò)誤。

useImperativeHandle

除了限制跨組件傳遞ref外,還有一種防止ref失控的措施,那就是useImperativeHandle,他的邏輯是這樣的:

既然ref失控是由于使用了不該被使用的DOM方法(比如appendChild),那我可以限制ref中只存在可以被使用的方法。

useImperativeHandle修改我們的MyInput組件:

const MyInput = forwardRef((props, ref) => {
  const realInputRef = useRef(null);
  useImperativeHandle(ref, () => ({
    focus() {
      realInputRef.current.focus();
    },
  }));
  return <input {...props} ref={realInputRef} />;
});

現(xiàn)在,Form組件中通過inputRef.current只能取到如下數(shù)據(jù)結(jié)構(gòu):

{
  focus() {
    realInputRef.current.focus();
  },
}

就杜絕了開發(fā)者通過ref取到DOM后,執(zhí)行不該被使用的API,出現(xiàn)ref失控的情況。

總結(jié)

正常情況,Ref的使用比較少,他是作為逃生艙而存在的。

為了防止錯(cuò)用/濫用導(dǎo)致ref失控,React限制默認(rèn)情況下,不能跨組件傳遞ref。

為了破除這種限制,可以使用forwardRef。

為了減少ref對(duì)DOM的濫用,可以使用useImperativeHandle限制ref傳遞的數(shù)據(jù)結(jié)構(gòu)。

以上就是React新文檔切記不要濫用Ref的詳細(xì)內(nèi)容,更多關(guān)于React新文檔Ref的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • create-react-app修改為多頁(yè)面支持的方法

    create-react-app修改為多頁(yè)面支持的方法

    本篇文章主要介紹了create-react-app修改為多頁(yè)面支持的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧
    2018-05-05
  • Input標(biāo)簽自動(dòng)校驗(yàn)功能去除實(shí)現(xiàn)

    Input標(biāo)簽自動(dòng)校驗(yàn)功能去除實(shí)現(xiàn)

    這篇文章主要為大家介紹了Input標(biāo)簽的自動(dòng)拼寫檢查功能去除實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07
  • React Hooks中模擬Vue生命周期函數(shù)的指南

    React Hooks中模擬Vue生命周期函數(shù)的指南

    React Hooks 提供了一種在函數(shù)組件中使用狀態(tài)和其他 React 特性的方式,而不需要編寫類組件,Vue 的生命周期函數(shù)和 React Hooks 之間有一定的對(duì)應(yīng)關(guān)系,本文給大家介紹了React Hooks中模擬Vue生命周期函數(shù)的指南,需要的朋友可以參考下
    2024-10-10
  • 詳解操作虛擬dom模擬react視圖渲染

    詳解操作虛擬dom模擬react視圖渲染

    這篇文章主要介紹了詳解操作虛擬dom模擬react視圖渲染,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧
    2018-07-07
  • redux功能強(qiáng)大的Middleware中間件使用學(xué)習(xí)

    redux功能強(qiáng)大的Middleware中間件使用學(xué)習(xí)

    這篇文章主要為大家介紹了redux功能強(qiáng)大的Middleware中間件使用學(xué)習(xí),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09
  • 解析TypeError:import_react_native.AppState.removeEventListener?is?not?a?function

    解析TypeError:import_react_native.AppState.removeEventListener

    這篇文章主要為大家介紹了TypeError:import_react_native.AppState.removeEventListener?is?not?a?function問題解決分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • React實(shí)現(xiàn)路由返回?cái)r截的三種方式

    React實(shí)現(xiàn)路由返回?cái)r截的三種方式

    最近項(xiàng)目為了避免用戶誤操作導(dǎo)致數(shù)據(jù)丟失,增加返回?cái)r截功能,但是之前由于qiankun的報(bào)錯(cuò)導(dǎo)致這個(gè)功能一直有一些問題,所以專門獨(dú)立搞了一個(gè)專題研究在react中各種方式實(shí)現(xiàn)這個(gè)功能,需要的朋友可以參考下
    2024-05-05
  • npx create-react-app xxx創(chuàng)建項(xiàng)目報(bào)錯(cuò)的解決辦法

    npx create-react-app xxx創(chuàng)建項(xiàng)目報(bào)錯(cuò)的解決辦法

    這篇文章主要介紹了npx create-react-app xxx創(chuàng)建項(xiàng)目報(bào)錯(cuò)的解決辦法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02
  • React 全面解析excel文件

    React 全面解析excel文件

    這篇文章主要介紹了React 全面解析excel文件,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • 基于react后端渲染模板引擎noox發(fā)布使用

    基于react后端渲染模板引擎noox發(fā)布使用

    本篇文章主要介紹了基于react后端渲染模板引擎noox發(fā)布使用,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧
    2018-01-01

最新評(píng)論

安溪县| 瑞金市| 虞城县| 滕州市| 天镇县| 平江县| 达州市| 耿马| 河南省| 永宁县| 铅山县| 金川县| 雅江县| 五峰| 介休市| 宁武县| 土默特左旗| 巴青县| 千阳县| 丹寨县| 工布江达县| 九江市| 石棉县| 东辽县| 鲁山县| 冕宁县| 梅州市| 沙河市| 延吉市| 陇西县| 徐闻县| 宜都市| 启东市| 台江县| 唐山市| 永新县| 綦江县| 得荣县| 太白县| 普安县| 措美县|