成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

React#31 error,讓我熬夜讓我禿

開發 前端
本篇給大家介紹封裝一個React組件交給業務方使用。希望對你有所幫助!

[[395739]]

卡頌日常從事基礎架構相關工作。這次接到一個任務:封裝一個React組件交給業務方使用。

組件本地開發無誤,自測無誤,交給業務方接入無誤,業務方測試環境驗收無誤。

然而,當包含該組件的頁面小流量上線后,監控平臺立刻收到報警:

  1. Minified React error #31 ...... 

打開監控看板,發現大部分報錯來自于一款機型:「Vivo x7」,Android版本5.1。完整報錯信息如下:

看看時間:周五晚上6點半。呵,還有我解決不了的React問題?半小時搞定,過周末去~

然而......

[[395740]]

找準問題原因

簡單描述下#31號錯誤信息描述的內容:

React的render函數可接受的返回值類型包括:

  • string,比如return 'I am kasong';
  • number,比如return 123;
  • array,比如return  [<p>ka</p>, <p>song</p>];。

其中[]會被處理為React.Fragment

  • object,比如return  <p>ka song</p>;。

因為該返回值會被編譯為React.createElement(或jsx.createElement,視React版本不同而不同)。

而React.createElement的返回值是一個對象(即object類型)。

這里的報錯信息是說:你某個組件返回了一個非法值。因為這個值是object類型,但是他不是一個JSX對象。

想要復現這個問題也很簡單,比如如下代碼:

  1. function App() { 
  2.   reutrn {}; 

返回值是個object,但非JSX對象。

作為React老司機,是絕對不可能寫錯返回值類型的。況且,寫錯的話,本地開發就會報錯了。

而且很奇怪,這個問題,為什么只在這款機型復現呢?

初見端倪

現在我們掌握的線索是:

  • 這是個個別機型復現的報錯
  • 報錯原因是因為render函數返回了錯誤的類型

我們需要更多線索!!

 [[395741]]

雖然是被壓縮的線上代碼,但好在React提供了必要的錯誤信息。

這個錯誤的object包含了如下字段:

  1. found: object with keys {$$typeof, type, key, ref, props, _owner}). 

居然包含$$typeof!!!

$$typeof是React源碼內部用來判斷JSX對象類型的字段。

比如React.Fragment、React.portal、div這三種JSX分別對應三種$$typeof。

換言之,包含$$typeof的object類型,大概率是一個JSX對象。

既然這個報錯的object對象就是一個JSX對象,那React為什么還認為他是一個非法的返回值呢?

 [[395742]]

React狠起來連自己都殺?

深入源碼

要解答這個問題,必須深入React源碼。

由于我的組件中沒有使用Fragment或Portal這樣的特性,所以將問題定位在普通React組件對應的$$typeof。

在源碼中,這種類型被稱為REACT_ELEMENT_TYPE。

  • PS:Fragment類型為REACT_FRAGMENT_TYPE,Portal類型為REACT_PORTAL_TYPE,
  1. var hasSymbol = typeof Symbol === 'function' && Symbol.for
  2. var REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for('react.element') : 0xeac7; 

可以看到,當宿主環境支持Symbol時,REACT_ELEMENT_TYPE === Symbol.for('react.element')。

不支持時,REACT_ELEMENT_TYPE === 0xeac7

與此同時,REACT_ELEMENT_TYPE這個變量的定義不僅存在于React這個包中,也存在于ReactDOM包中。

Vivo x7的webview原生不支持Symbol。似乎有點兒苗頭了!

審查業務方代碼后發現,業務方使用core-js實現了Symbol polyfill。

那么設想如下場景:

假如業務方代碼打包的順序是:

  1. React -> core-js -> ReactDOM 

那么在運行時,React首先加載,執行到定義REACT_ELEMENT_TYPE變量這行代碼時,宿主環境全局不存在Symbol。

所以在React這個包中,REACT_ELEMENT_TYPE === 0xeac7

接著運行core-js,他會在window上掛載Symbol。

接著ReactDOM在運行時,執行到定義REACT_ELEMENT_TYPE變量這行代碼時,宿主環境已經存在全局變量Symbol。

所以在ReactDOM中,REACT_ELEMENT_TYPE === Symbol.for('react.element')

而React.createElement方法來自React包,組件的render方法是在ReactDOM包中的reconciler模塊調用的,

所以就會發生判斷組件類型時,0xeac7 !== Symbol.for('react.element'),讓React認為這是個非法的返回值。

在遙遠的2016年,就有人就此給React提issue[1]

事實真的如此么?

然而審視業務方代碼后發現,依賴打包的順序是:

  1. core-js -> React -> ReactDOM 

按照剛才的推理,React和ReactDOM都能拿到core-js提供的Symbol polyfill。

[[395743]]

撥云見日

此時早已華燈初上,我為我對React的輕視流下了不爭氣的淚水。

虧我還是React Contributor,React技術揭秘[2]作者,React 17的源碼方法名都能背下來。

嗯?React 17??難道!

[[395744]]

v16.14之前版本的React中JSX對象會被編譯為React.createElement。

此版本之后createElement被從React包中拆分出來,獨立在react/jsx-runtime中。

編譯工作則由@babel/plugin-transform-react-jsx插件完成。

那么此時,REACT_ELEMENT_TYPE的定義存在于jsx-runtime、React、ReactDOM三個包中。

也就是說,如果編譯后包的執行順序是:

  1. jsx-runtime -> core-js -> React -> ReactDOM 

在低端Android機上還會復現這個問題!

這里截取一個網友遇到同樣問題后他的截圖:

  • 這個問題的討論見Bug: IE 11 not working with latest React version

可以看到,jsx-runtime被babel編譯成第一個依賴,破案!

所以,這實際上是個babel編譯后產物順序造成的bug,已經有人給babel提相關issue[3]

最終我將JSX的編譯方式從編譯為jsx.createElement降級為React.createElement解決了這個報錯。

此時,夜已深。。。

總結

每一片雪花都是那么純潔,直到他們組成了一場雪崩。

這個bug的各方,React、babel、提供組件的我、業務方代碼,單獨來看,沒有一方有問題。

但是,當一系列巧合合并在一起,就是一個線上bug。

這也顯示了線上小流量、報錯監控基建的重要性。

參考資料

[1]issue:

https://github.com/facebook/react/issues/8379#issuecomment-264858787

[2]React技術揭秘:

http://react.iamkasong.com/

[3]issue:

https://github.com/babel/babel/issues/12522

[4]React官網鏈接:

https://reactjs.org/docs/error-decoder.html/?invariant=31&args[]=object%20with%20keys%20%7B%E6%AC%A2%E8%BF%8E%E5%85%B3%E6%B3%A8%2C%20%E6%88%91%E7%9A%84%E5%85%AC%E4%BC%97%E5%8F%B7%2C%20%E9%AD%94%E6%9C%AF%E5%B8%88%E5%8D%A1%E9%A2%82%2C%20%E4%B8%93%E6%B3%A8React%E6%8A%80%E6%9C%AF%E6%A0%88%2C%20%E5%92%8C%E5%B0%8F%E4%BC%99%E4%BC%B4%E4%BB%AC%2C%20%E4%B8%80%E8%B5%B7%E8%BF%9B%E6%AD%A5%7D&args[]=%20for%20the%20full%20message%20or%20use%20the%20non-minified%20dev%20environment%20for%20full%20errors%20and%20additional%20helpful%20warnings.

 

責任編輯:姜華 來源: 魔術師卡頌
相關推薦

2023-06-26 07:10:51

2025-04-08 11:30:00

DIM數據倉庫架構

2023-04-13 13:03:25

信息技術ChatGPT失業

2014-05-23 10:25:48

Clojure

2023-03-30 13:56:38

ChatGPT

2013-01-24 13:31:47

BMCMyIT

2021-09-01 11:45:10

Spring循環依賴面試

2021-09-06 06:45:06

普通索引唯一

2021-05-30 12:27:54

策略模式算法

2021-04-12 18:03:39

Nginx架構負載

2014-03-06 15:48:37

李奕泓編程程序媛

2020-12-21 08:32:07

內存性能優化

2022-03-02 15:14:09

訂單計時器持久化

2022-04-29 08:00:36

web3區塊鏈比特幣

2011-06-27 08:35:28

2012-07-25 09:56:52

編程程序員

2011-02-22 17:40:54

konqueror

2023-06-06 08:20:07

運維Spring內存

2011-09-16 09:06:20

Smalltalk

2021-09-11 19:02:34

Hook使用版本
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日本特黄a级高清免费大片 成年人黄色小视频 | 亚洲成人一区二区 | 亚洲精品久久久久久久不卡四虎 | 久久99深爱久久99精品 | 国产一级一片免费播放 | 精品一区国产 | 日本三级网址 | 日韩欧美二区 | 国产成人一区二区三区精 | 天天综合操| 亚洲精品成人av久久 | 日韩播放| av在线三级| 91麻豆精品国产91久久久更新资源速度超快 | 精品免费视频一区二区 | 久久偷人| 一级黄色短片 | 欧美日韩在线高清 | 免费av直接看 | 一区二区三区电影在线观看 | 伊人99| 日韩精品一区二区三区视频播放 | 亚洲成人免费视频 | 国产精品亚洲成在人线 | 午夜视频在线观看视频 | 伊人亚洲 | 日本在线网站 | 亚洲精品一区二区 | 久久精品中文 | 99精品视频免费观看 | a级片网站 | 国产高清精品在线 | 国产亚洲精品综合一区 | 免费网站国产 | 精品久久久久久久久久久久久久 | 做a视频 | 成人亚洲视频 | 国产四虎 | 精品久久久久一区 | 国内精品久久久久 | 精品少妇一区二区三区日产乱码 |