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

React新文檔切記不要濫用Ref

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

引言

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

顯然,正常航行時是不需要逃生艙的,只有在遇到危險時會用到。

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

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

今天,我們來聊聊Ref的使用場景。

為什么是逃生艙?

先思考一個問題:為什么refeffect被歸類到逃生艙中?

這是因為二者操作的都是脫離React控制的因素。

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

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

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

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

失控的Ref

對于Ref,什么叫失控呢?

首先來看不失控的情況:

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

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

但是下面的情況:

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

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

舉個例子,下面是React文檔中的例子

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

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é)點。

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

如果這兩種移除P節(jié)點的方式混用,那么先點擊按鈕1再點擊按鈕2就會報錯:

這就是使用Ref操作DOM造成的失控情況導致的。

如何限制失控

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

React中,組件可以分為:

  • 高階組件
  • 低階組件

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

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/>
    </>
  )
}

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

文檔中的示例為例,如果我們想在Form組件中點擊按鈕,操作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>
    </>
  );
}

點擊后,會報錯:

這是因為在Form組件中向MyInput傳遞ref失敗了,inputRef.current并沒有指向input節(jié)點。

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

人為取消限制

如果一定要取消這個限制,可以使用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)。

在實踐中,一些同學可能覺得forwardRef這一API有些多此一舉。

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

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

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的使用比較少,他是作為逃生艙而存在的。

為了防止錯用/濫用導致ref失控,React限制默認情況下,不能跨組件傳遞ref。

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

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

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

相關(guān)文章

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

    React key值的作用和使用詳解

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

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

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

    詳解React?hooks組件通信方法

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

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

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

    React實現(xiàn)分頁效果

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

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

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

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

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

    深入了解React中的虛擬DOM

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

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

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

    詳解Redux的工作流程

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

最新評論