欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

React新文檔切記不要濫用Ref

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

引言

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

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

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

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

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

為什么是逃生艙?

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

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

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

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

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

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

失控的Ref

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

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

  • 執(zhí)行ref.currentfocus、blur等方法
  • 執(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)的因素,通過(guò)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通過(guò)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)在問(wèn)題來(lái)了,既然叫失控了,那就是React沒(méi)法控制的(React總不能限制開(kāi)發(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并沒(méi)有指向input節(jié)點(diǎn)。

究其原因,就是上面說(shuō)的為了將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é)可能覺(jué)得forwardRef這一API有些多此一舉。

但從ref失控的角度看,forwardRef的意圖就很明顯了:既然開(kāi)發(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組件中通過(guò)inputRef.current只能取到如下數(shù)據(jù)結(jié)構(gòu):

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

就杜絕了開(kāi)發(fā)者通過(guò)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)文章

  • React key值的作用和使用詳解

    React key值的作用和使用詳解

    這篇文章主要介紹了React key值的作用和使用詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-08-08
  • React?在非組件環(huán)境切換路由的方法

    React?在非組件環(huán)境切換路由的方法

    這篇文章主要介紹了React?在非組件環(huán)境切換路由的方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2023-10-10
  • 詳解React?hooks組件通信方法

    詳解React?hooks組件通信方法

    這篇文章主要介紹了React?hooks組件通信,在開(kāi)發(fā)中組件通信是React中的一個(gè)重要的知識(shí)點(diǎn),本文通過(guò)實(shí)例代碼給大家講解react hooks中常用的父子、跨組件通信的方法,需要的朋友可以參考下
    2022-07-07
  • React props和state屬性的具體使用方法

    React props和state屬性的具體使用方法

    本篇文章主要介紹了React props和state屬性的具體使用方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-04-04
  • React實(shí)現(xiàn)分頁(yè)效果

    React實(shí)現(xiàn)分頁(yè)效果

    這篇文章主要為大家詳細(xì)介紹了React實(shí)現(xiàn)分頁(yè)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • 模塊化react-router配置方法詳解

    模塊化react-router配置方法詳解

    這篇文章主要介紹了模塊化react-router配置方法詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-06-06
  • 使用webpack配置react-hot-loader熱加載局部更新

    使用webpack配置react-hot-loader熱加載局部更新

    這篇文章主要介紹了使用webpack配置react-hot-loader熱加載局部更新,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • 深入了解React中的虛擬DOM

    深入了解React中的虛擬DOM

    歡迎來(lái)到今天的探險(xiǎn)之旅!在這篇博客中,我們將深入了解 React 中神奇的虛擬DOM,并通過(guò)一個(gè)簡(jiǎn)單的例子來(lái)揭開(kāi)其神秘面紗,文中通過(guò)代碼示例也講解非常詳細(xì),感興趣的朋友可以參考下
    2024-01-01
  • React+TypeScript+webpack4多入口配置詳解

    React+TypeScript+webpack4多入口配置詳解

    這篇文章主要介紹了React+TypeScript+webpack4多入口配置詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • 詳解Redux的工作流程

    詳解Redux的工作流程

    這篇文章主要介紹了Redux的工作流程,redux是一個(gè)專(zhuān)門(mén)用于做狀態(tài)管理的JS庫(kù),它可以在react、angular、vue等項(xiàng)目中,但基本與react配合使用,需要的朋友可以參考下
    2022-08-08

最新評(píng)論