React 16 升級到 17 的一個(gè)坑:組件銷毀時(shí) ref 可能會被重置為 null

大家好屹徘,我是前端西瓜哥。

最近公司的項(xiàng)目用的 React 從 16 升到了 17 版本匕荸,選擇升級的原因是想以后將項(xiàng)目遷移到 Nextjs 上车摄。

結(jié)果發(fā)現(xiàn)因?yàn)?React 的行為不一致導(dǎo)致了一些看得見的和看不見的 bug,真的是一場災(zāi)難奏寨。

React 17 是一個(gè)比較特別的版本起意,它沒有任何新特性,但它改造了 React 的底層病瞳,讓 React 17 可以漸進(jìn)式地升級部分的模塊揽咕,為 18 版本做準(zhǔn)備。

這些改造套菜,有一部分是破壞性的亲善。

問題

我這里有個(gè)彈窗,彈窗里面是一些表單項(xiàng)逗柴。當(dāng)用戶在表單項(xiàng)做了一些修改蛹头,然后點(diǎn)擊彈窗的遮罩層時(shí),里面的組件會銷毀掉戏溺。

在銷毀時(shí)渣蜗,我們會調(diào)用一個(gè) ref 上的 save() 方法來保存這些數(shù)據(jù)。

useEffect(()?=>?{
??return?()?=>?{
????formRef.current?&&?formRef.current.save();
??}
},?[]);

在 React 16 的時(shí)候是正常的旷祸,但到 React 17耕拷,失敗了,我們無法保存表單里面的數(shù)據(jù)托享。

一頓排查之后骚烧,我找到了問題所在:在 React 17 版本,組件銷毀時(shí)獲取的 ref.current 可能會被重置為 null闰围。

接著我找到了官方文檔對于這種情況的說明:

https://zh-hans.reactjs.org/blog/2020/08/10/react-v17-rc.html#effect-cleanup-timing

useEffect 的清理時(shí)機(jī)

useEffect(()?=>?{
?return?()?=>?{
????//?這里的執(zhí)行清理操作
??}
})

在 React 17 中赃绊,副作用的執(zhí)行時(shí)機(jī)發(fā)生了變化,一個(gè)破壞性的效果是:如果組件卸載辫诅,副作用的清理時(shí)機(jī)是異步的凭戴,對應(yīng)的回調(diào)函數(shù)執(zhí)行也同樣是異步的。是的炕矮,異步么夫。

卸載時(shí)的要執(zhí)行的回調(diào)函數(shù)者冤,對于狀態(tài)和方法的訪問,問題不大档痪,它們是不可變的涉枫,能通過閉包的方式訪問到的。

但問題是 ref腐螟,它是可變的愿汰,我們可以隨意的設(shè)置 ref.current 的值,且不會觸發(fā)組件的重新渲染乐纸。

這個(gè) ref 會被 React 在組件卸載時(shí)重置為 null衬廷。因?yàn)槭钱惒降模晕覀冇泻艽罂赡軙蔡嵋粋€(gè) null 值汽绢。

這里有一個(gè)簡單的在線 demo吗跋,感興趣可以看看,當(dāng) Component 組件銷毀時(shí)宁昭,elRef 變成了 null:

https://codesandbox.io/s/react-17-zhong-zu-jian-xiao-hui-shi-ref-ke-neng-bei-she-zhi-wei-null-2kl4xu

然后是 React 16 版本的 ref跌宛,因?yàn)槭峭降模凿N毀時(shí) ref 沒有重置為 null:

https://codesandbox.io/s/16-de-ref-shi-zheng-chang-de-18mqmd

解決方案

官方的文檔提供了兩個(gè)解決方案积仗。

一個(gè)是用 useLayoutEffect疆拘。

useLayoutEffect(()?=>?{
??return?()?=>?{
????formRef.current?&&?formRef.current.save();
??}
},?[]);

useLayoutEffect 可以保證回調(diào)函數(shù) 同步 執(zhí)行,這樣就能確保 ref 此時(shí)還是最后的值寂曹,而不是被設(shè)置為 null哎迄。

第二種方式是用一個(gè)臨時(shí)變量在 ref 每次變化時(shí),將 ref.current 保存起來稀颁,放到副作用清理回調(diào)函數(shù)的閉包中芬失,來保證不可變性。

useEffect(()?=>?{
??const?instance?=?someRef.current;
??instance.someSetupMethod();
??return?()?=>?{
????instance.someCleanupMethod();
??};
});

但這里貌似還是有一點(diǎn)局限性:不能提供第二個(gè)參數(shù)匾灶,也就是依賴項(xiàng)參數(shù),因?yàn)槲覀儾荒鼙WC中途 ref 沒有發(fā)生改變租漂。

目前我是用第一種方案來處理我遇到的問題阶女。

結(jié)尾

版本升級這件事情,還是得權(quán)衡利弊哩治。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末秃踩,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子业筏,更是在濱河造成了極大的恐慌憔杨,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蒜胖,死亡現(xiàn)場離奇詭異消别,居然都是意外死亡抛蚤,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進(jìn)店門寻狂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來岁经,“玉大人,你說我怎么就攤上這事蛇券∽喝溃” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵纠亚,是天一觀的道長塘慕。 經(jīng)常有香客問我,道長蒂胞,這世上最難降的妖魔是什么图呢? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮啤誊,結(jié)果婚禮上岳瞭,老公的妹妹穿的比我還像新娘。我一直安慰自己蚊锹,他們只是感情好瞳筏,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著牡昆,像睡著了一般姚炕。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上丢烘,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天柱宦,我揣著相機(jī)與錄音,去河邊找鬼播瞳。 笑死掸刊,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的赢乓。 我是一名探鬼主播忧侧,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼牌芋!你這毒婦竟也來了蚓炬?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤躺屁,失蹤者是張志新(化名)和其女友劉穎肯夏,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡驯击,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年烁兰,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片余耽。...
    茶點(diǎn)故事閱讀 39,785評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡缚柏,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出碟贾,到底是詐尸還是另有隱情币喧,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布袱耽,位于F島的核電站杀餐,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏朱巨。R本人自食惡果不足惜史翘,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望冀续。 院中可真熱鬧琼讽,春花似錦、人聲如沸洪唐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽凭需。三九已至问欠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間粒蜈,已是汗流浹背顺献。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留枯怖,地道東北人注整。 一個(gè)月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像度硝,于是被迫代替她去往敵國和親设捐。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評論 2 354

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