av激情亚洲男人的天堂国语,日韩欧美精品一中文字幕,无码av一区二区三区无码,国产又色又爽又刺激的a片,国产又色又爽又刺激的a片

React新文檔:不要濫用Ref哦!

大家好,我卡頌。

創(chuàng)新互聯(lián)是一家集網(wǎng)站建設(shè),新疆企業(yè)網(wǎng)站建設(shè),新疆品牌網(wǎng)站建設(shè),網(wǎng)站定制,新疆網(wǎng)站建設(shè)報(bào)價(jià),網(wǎng)絡(luò)營銷,網(wǎng)絡(luò)優(yōu)化,新疆網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強(qiáng)企業(yè)競(jìng)爭(zhēng)力??沙浞譂M足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時(shí)我們時(shí)刻保持專業(yè)、時(shí)尚、前沿,時(shí)刻以成就客戶成長(zhǎng)自我,堅(jiān)持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實(shí)用型網(wǎng)站。

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

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

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

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

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

為什么是逃生艙?

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

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

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

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

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

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

失控的Ref

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

首先來看「不失控」的情況:

  • 執(zhí)行ref.current的focus、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)的因素」,通過ref執(zhí)行這些操作就屬于失控的情況。

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

「按鈕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 (

onClick={() => {
setShow(!show);
}}>
Toggle with setState

onClick={() => {
ref.current.remove();
}}>
Remove from the DOM

{show &&

Hello world

}

);
}

「按鈕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)在問題來了,既然叫「失控」了,那就是React沒法控制的(React總不能限制開發(fā)者不能使用DOM API吧?),那如何限制失控呢?

在React中,組件可以分為:

  • 高階組件
  • 低階組件

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

function MyInput(props) {
return ;
}

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

function MyInput(props) {
const ref = useRef(null);
return ;
}

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

function Form() {
return (
<>


)
}

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

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

function MyInput(props) {
return ;
}
function Form() {
const inputRef = useRef(null);
function handleClick() {
inputRef.current.focus();
}
return (
<>



);
}

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

這是因?yàn)樵贔orm組件中向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 ;
});
function Form() {
const inputRef = useRef(null);
function handleClick() {
inputRef.current.focus();
}
return (
<>



);
}

使用forwardRef(forward在這里是「?jìng)鬟f」的意思)后,就能跨組件傳遞ref。

在例子中,我們將inputRef從Form跨組件傳遞到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 ;
});

現(xiàn)在,F(xiàn)orm組件中通過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)。

參考資料

[1]React文檔中的例子:https://codesandbox.io/s/sandpack-project-forked-s33q3c。

[2]文檔中的示例:https://codesandbox.io/s/sandpack-project-forked-7zqgmd。


當(dāng)前標(biāo)題:React新文檔:不要濫用Ref哦!
瀏覽地址:http://uogjgqi.cn/article/dhhesip.html
掃二維碼與項(xiàng)目經(jīng)理溝通

我們?cè)谖⑿派?4小時(shí)期待你的聲音

解答本文疑問/技術(shù)咨詢/運(yùn)營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流