翻譯:瘋狂的技術(shù)宅
原文:https://www.toptal.com/react/react-tutorial-pt2
正如 我們的React教程第一部分 【點(diǎn)擊直達(dá)】中所指出的岳掐,開始使用 React 相對容易邑跪。首先使用 Create React App(CRA)初始化一個(gè)新項(xiàng)目榜轿,然后開始開發(fā)亥贸。不過遺憾的是,隨著時(shí)間的推移讯嫂,代碼可能會變得難以維護(hù)蹦锋,特別是在你不熟悉 React 的情況下。組件有可能會變大欧芽,或者你可能最終得到一堆不是組件的組件莉掂,最終你可能會到處編寫重復(fù)的代碼。
這時(shí)候你就應(yīng)該試著開始真正的 React 之旅了 —— Think in React千扔。
每當(dāng)開發(fā)一個(gè)新的程序時(shí)憎妙,你需要為其做好在以后轉(zhuǎn)換為 React 應(yīng)用的新設(shè)計(jì),首先試著確定設(shè)計(jì)草圖中的組件曲楚,如何分離它們以使其更易于管理厘唾,以及哪些元素是重復(fù)的(或他們的行為)。盡量避免添加可能“將來有用”的代碼 —— 雖然這很誘人龙誊,但可能未來永遠(yuǎn)也不會到來抚垃,你將留下一堆具有大量可配置選項(xiàng)的多余通用功能/組件。
<figcaption style="margin: 10px 0px 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; line-height: inherit; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em;">React 組件</figcaption>
此外载迄,如果一個(gè)組件大于 2 到 3 個(gè)窗口的高度讯柔,也許值得分離(如果可能的話) —— 以后更容易閱讀。
React 中的受控組件與非受控組件
在大多數(shù)應(yīng)用中护昧,需要輸入和與用戶進(jìn)行某種形式的交互,允許他們輸入內(nèi)容粗截、上傳文件惋耙、選擇字段等。 React 用兩種不同的方式處理用戶交互 —— 受控和非受控組件熊昌。
顧名思義绽榛,受控組件的值由 React 控制,能為與用戶交互的元素提供值婿屹,而不受控制的元素不獲取值屬性灭美。多虧了這一點(diǎn),我們才能把 React 狀態(tài)作為單一的事實(shí)來源昂利,因此我們在屏幕上看到的與當(dāng)前擁有的狀態(tài)是一致的届腐。開發(fā)人員需要傳遞一個(gè)函數(shù),該函數(shù)用來響應(yīng)用戶與表單的交互蜂奸,這將會改變它的狀態(tài)犁苏。
1class ControlledInput extends React.Component { 2 state = { 3 value: "" 4 }; 5 6 onChange = (e) => this.setState({ value: e.target.value }); 7 8 render() { 9 return (10 <input value={this.state.value} onChange={this.onChange}/>11 );12 }13}14
在 React 的非受控組件中,我們不關(guān)心值的變化情況扩所,如果想要知道其確切的值围详,只需通過 ref 訪問它。
1class UncontrolledInput extends React.Component { 2 input = React.createRef(); 3 4 getValue = () => { 5 console.log(this.input.current.value); 6 }; 7 8 render() { 9 return (10 <input ref={this.input}/>11 );12 }13}14
那么應(yīng)該怎么選擇呢祖屏?在大數(shù)情況下用受控組件是可行的助赞,不過也有一些例外买羞。例如使用非受控制組件的一種情況是 file
類型輸入,因?yàn)樗闹凳侵蛔x的雹食,不能在編碼中去設(shè)置(需要用戶交互)哩都。另外我發(fā)現(xiàn)受控組件更容易理解和于使用。對受控組件的驗(yàn)證是基于重新渲染的婉徘,狀態(tài)可以更改漠嵌,并且可以很輕松的顯示輸入中存在的問題(例如格式錯(cuò)誤或者輸入為空)。
Refs
在前面我們提到過 refs
盖呼,這是一個(gè)特殊功能儒鹿,可以在類組件中使用,直到 16.8 中出現(xiàn)了 hooks几晤。
refs 可以通過引用讓開發(fā)人員訪問 React 組件或DOM元素(取決于我們附加 ref 的類型)约炎。最好僅在必須的場景中使用它們,因?yàn)樗鼈儠勾a難以閱讀蟹瘾,并打破從上到下的數(shù)據(jù)流圾浅。然而,有些情況下它們是必要的憾朴,特別是在DOM元素上(例如:用編碼方式改變焦點(diǎn))狸捕。附加到 React 組件元素時(shí),你可以自由使用所引用的組件中的方法众雷。不過還是應(yīng)該避免這種做法灸拍,因?yàn)橛懈玫姆椒▉硖幚硭ɡ纾嵘隣顟B(tài)并將功能移動到父組件)砾省。
refs 還可以做到:
使用字符串字面量(歷史遺留的鸡岗,應(yīng)該避免),
使用在 ref 屬性中設(shè)置的回調(diào)函數(shù)编兄,
通過創(chuàng)建 ref 作為
React.createRef()
轩性,并將其綁定到類屬性,并通過它去訪問(請注意狠鸳,在 componentDidMount 生命周期中將提供引用)揣苏。
沒有傳遞引用的一種情況是當(dāng)在組件上使用高階組件時(shí) —— 原因是可以理解的,因?yàn)?ref
不是 prop
(類似于 key
)所以它沒有被傳遞下來碰煌,并且它將引用 HOC
而不是被它包裹的組件舒岸。在這種情況下,我們可以使用React.forwardRef
芦圾,它把 props 和 ref 作為參數(shù)蛾派,然后可以將其分配給 prop
并傳遞給我們想要訪問的組件。
1function withNewReference(Component) { 2 class Hoc extends React.Component { 3 render() { 4 const {forwardedRef, ...props} = this.props; 5 6 return <Component ref={forwardedRef} {...props}/>; 7 } 8 } 910 return React.forwardRef((props, ref) => {11 return <Hoc {...props} forwardedRef={ref} />;12 });13}
錯(cuò)誤邊界
事情越復(fù)雜,出現(xiàn)問題的概率就越高洪乍。這就是為什么 React 中會有錯(cuò)誤邊界眯杏。那他們是怎么工作的呢?
如果出現(xiàn)問題并且沒有錯(cuò)誤邊界作為其父級壳澳,則會導(dǎo)致整個(gè)React 應(yīng)用失敗岂贩。不顯示信息比誤導(dǎo)用戶并顯示錯(cuò)誤信息要好,但這并不意味著你應(yīng)該放任整個(gè)應(yīng)用崩潰并顯示白屏巷波。通過錯(cuò)誤邊界萎津,可以得到更多的靈活性。你可以在整個(gè)應(yīng)用程序中使用并顯示一個(gè)錯(cuò)誤消息抹镊,或者在某些小部件中使用它但是不顯示锉屈,或者顯示少量信息來代替這些小部件。
請記住垮耳,它僅涉及聲明性代碼的問題颈渊,而不是你為了處理某些事件或者調(diào)用而編寫的命令式代碼。對于這些情況终佛,你仍應(yīng)使用常規(guī)的 try/catch 方法俊嗽。
在錯(cuò)誤邊界也可以將信息發(fā)送到你使用的 Error Logger (在 componentDidCatch
生命周期方法中)。
1class ErrorBoundary extends React.Component { 2 state = { hasError: false }; 3 4 static getDerivedStateFromError(error) { 5 return { hasError: true }; 6 } 7 8 componentDidCatch(error, info) { 9 logToErrorLogger(error, info);10 }1112 render() {13 if (this.state.hasError) {14 return <div>Help, something went wrong.</div>;15 }1617 return this.props.children; 18 }19}
高階組件
高階組件(HOC)經(jīng)常在 React 中被提及铃彰,這是一種非常流行的模式绍豁,你可能會用到它(或者已經(jīng)在用了)。如果你熟悉 HOC豌研,可能已經(jīng)在很多庫中看到過 withNavigation妹田,connect,withRouter
鹃共。
HOC 只是一種把組件作為參數(shù)的函數(shù),并且與沒有 HOC 包裝器的組件相比驶拱,能夠返回具有擴(kuò)展功能的新組件霜浴。多虧了這一點(diǎn),你可以實(shí)現(xiàn)一些易于擴(kuò)展的功能蓝纲,以此增強(qiáng)自己的組件(例如:訪問導(dǎo)航)阴孟。 HOC 也有一些其它形式的調(diào)用方式,這取決于我們當(dāng)前擁有什么税迷,唯一的參數(shù)必須要傳入一個(gè)組件永丝,但它也可以接受額外的參數(shù) —— 一些選項(xiàng),或者像在 connect
中一樣箭养,首先使用configurations調(diào)用一個(gè)函數(shù)慕嚷,該函數(shù)稍后返回一個(gè)帶參組件,并返回 HOC 。
以下是一些你應(yīng)該做的和要避免做的事情:
為包裝器 HOC 函數(shù)添加顯示名稱(這樣你就能知道它到底是干什么用的喝检,實(shí)際上是通過更改 HOC 組件顯示名稱來做到)嗅辣。
不要在渲染方法中使用HOC —— 你應(yīng)該在其中使用增強(qiáng)組件,而不是在那里創(chuàng)建新的 HOC 組件挠说,因?yàn)樗恢痹谥匦卵b載并丟失其當(dāng)前狀態(tài)澡谭。
靜態(tài)方法不會被自動復(fù)制,所以如果你想在新創(chuàng)建的 HOC 中使用一些靜態(tài)方法损俭,需要自己去復(fù)制它們蛙奖。
涉及到的 Refs 不會被傳遞,所以使用前面提到的
React.forwardRef
來解決這些問題杆兵。
1export function importantHoc() { 2 return (Component) => class extends React.Component { 3 importantFunction = () => { 4 console.log("Very Important Function"); 5 }; 6 7 render() { 8 return ( 9 <Component10 {...this.props}11 importantFunction={this.importantFunction}12 />13 );14 }15 };16}17
樣式
樣式不一定與 React 本身有關(guān)雁仲,但出于各種原因還是值得一提的。
首先拧咳,常規(guī) CSS/內(nèi)聯(lián)樣式在這里能夠正常應(yīng)用伯顶,你只需在 className 屬性中添加 CSS 中的類名,它就能正常工作骆膝。內(nèi)聯(lián)樣式與常規(guī) HTML 樣式略有不同祭衩。樣式屬性也是使用駝峰命名法,因此 border-radius 會變成 borderRadius 阅签。
React 似乎推廣了一些不僅在 React 中變得普遍的解決方案掐暮,例如最近集成在 CRA 中的 CSS 模塊,你可以在其中簡單地導(dǎo)入 name.modules.css
并用其屬性來調(diào)整組件的樣式(某些IDE(例如WebStorm)也具有自動完成功能政钟,能告訴你可用的名稱路克。
在 React 中另一個(gè)流行的解決方案是 CSS-in-JS(例如,emotion
庫)养交。再說一點(diǎn)精算,CSS 模塊和 emotion(或者一般來說是CSS-in-JS)對 React 沒有限制。
React 中的 Hooks
自重寫以來碎连,**Hooks **很可能是 React 最受熱切期待的補(bǔ)充灰羽。這個(gè)產(chǎn)品是否能不負(fù)眾望?從我的角度來看鱼辙,是的廉嚼,因?yàn)樗_實(shí)是一個(gè)很棒的功能。它們本質(zhì)上是帶來了新的體驗(yàn)倒戏,例如:
允許刪除許多
class
組件怠噪,這些組件我們僅僅是使用而不歸我們擁有,例如本地狀態(tài)或 ref杜跷,所以組件的代碼看上去更容易閱讀傍念。可以讓你用更少的代碼來獲得相同的效果矫夷。
使函數(shù)更容易理解和測試,例如:用 react-testing-library【https://github.com/kentcdodds/react-testing-library】捂寿。
也可以攜帶參數(shù)口四,一個(gè) hook 返回的結(jié)果可以很容易地被另一個(gè) hook 使用(例如,
useEffect
中的setState
被useState
使用)秦陋。比類更好地縮小方式蔓彩,這對于 minifiers 來說往往更成問題。
可能會刪除 HOC 并在你的應(yīng)用中渲染 props 驳概,盡管 hook 被設(shè)計(jì)用于解決其他問題赤嚼,但仍會引入新問題。
能夠被熟練的React開發(fā)人員定制
默認(rèn)的 React hook 很少顺又。其中三個(gè)基本的hook是 useState
更卒,useEffect
和 useContext
。還有一些其它的稚照,例如 useRef
和 useMemo
蹂空,不過現(xiàn)在我們把重點(diǎn)放在基礎(chǔ)知識上。
先看一下 useState
果录,讓我們用它來創(chuàng)建一個(gè)簡單的計(jì)數(shù)器的上枕。它是如何工作的?基本上整個(gè)結(jié)構(gòu)非常簡單:
1export function Counter() { 2 const [counter, setCounter] = React.useState(0); 3 4 return ( 5 <div> 6 {counter} 7 <button onClick={() => setCounter(counter + 1)}>+</button> 8 </div> 9 );10};
它用 initialState
(值)調(diào)用弱恒,并返回一個(gè)帶有兩個(gè)元素的數(shù)組辨萍。由于數(shù)組解構(gòu)分配,我們可以立即將變量分配給這些元素返弹。第一個(gè)是更新后的最后一個(gè)狀態(tài)锈玉,而另一個(gè)是我們將用于更新值的函數(shù)∫迤穑看起來相當(dāng)容易拉背,不是嗎?
此外默终,由于這些組件曾經(jīng)被稱為無狀態(tài)功能組件去团,現(xiàn)在這種名稱不再適用,因?yàn)樗鼈兛梢跃哂腥缟纤镜臓顟B(tài)穷蛹。所以叫類組件和函數(shù)組件似乎更符合它們的實(shí)際操作,至少從16.8.0開始昼汗。
更新函數(shù)(在我們的例子中是setCounter
)也可以用作一個(gè)函數(shù)肴熏,它將以前的值作為參數(shù),格式如下:
1<button onClick={() => setCounter(prevCounter => prevCounter + 1)}>+</button>2<button onClick={() => setCounter(prevCounter => prevCounter - 1)}>-</button>
與執(zhí)行淺合并的this.setState
類組件不同顷窒,設(shè)置函數(shù)(在我們的例子中為 setCounter
)會覆蓋整個(gè)狀態(tài)蛙吏。
另外源哩,initialState
也可以是一個(gè)函數(shù),而不僅僅是一個(gè)普通的值鸦做。這有其自身的好處励烦,因?yàn)樵摵瘮?shù)將會只在組件的初始渲染期間運(yùn)行,之后將不再被調(diào)用泼诱。
1const [counter, setCounter] = useState(() => calculateComplexInitialValue());
最后坛掠,如果我們要使用 setCounter
與在當(dāng)前狀態(tài)(counter
)的同一時(shí)刻完全相同的值,那么組件 將不會 重新渲染治筒。
另一方面屉栓,useEffect
為我們的功能組件添加副作用,無論是訂閱耸袜、API調(diào)用友多、計(jì)時(shí)器、還是任何我們認(rèn)為有用的東西堤框。我們傳給 useEffect
的任何函數(shù)都將在 render 之后運(yùn)行域滥,并且是在每次渲染之后執(zhí)行,除非我們添加一個(gè)限制蜈抓,把應(yīng)該重新運(yùn)行時(shí)需要更改的屬性作為函數(shù)的第二個(gè)參數(shù)启绰。如果我們只想在 mount 上運(yùn)行它并在unmount 上清理,那么只需要在其中傳遞一個(gè)空數(shù)組资昧。
1const fetchApi = async () => { 2 const value = await fetch("https://jsonplaceholder.typicode.com/todos/1"); 3 console.log(await value.json()); 4}; 5 6export function Counter() { 7 const [counter, setCounter] = useState(0); 8 useEffect(() => { 9 fetchApi();10 }, []);111213 return (14 <div>15 {counter}16 <button onClick={() => setCounter(prevCounter => prevCounter + 1)}>+</button>17 <button onClick={() => setCounter(prevCounter => prevCounter - 1)}>-</button>18 </div>19 );20};
由于把空數(shù)組作為第二個(gè)參數(shù)酬土,所以上面的代碼只運(yùn)行一次。在這種情況下它類似于 componentDidMount
格带,但稍后會觸發(fā)它撤缴。如果你想在瀏覽器處理之前調(diào)用一個(gè)類似的 hook,可以用 useLayoutEffect
叽唱,但這些更新將會被同步應(yīng)用屈呕,這一點(diǎn)與 useEffect
不同。
useContext
似乎是最容易理解的棺亭,因?yàn)槲覀兲峁┝讼胍L問的上下文(由 createContext
函數(shù)返回的對象提供)虎眨,而它為我們提供了該上下文的值。
1const context = useContext(Context);
最后镶摘,要編寫自己的hook嗽桩,你可以像這樣寫:
1function useWindowWidth() { 2 let [windowWidth, setWindowWidth] = useState(window.innerWidth); 3 4 function handleResize() { 5 setWindowWidth(window.innerWidth); 6 } 7 8 useEffect(() => { 9 window.addEventListener('resize', handleResize);10 return () => window.removeEventListener('resize', handleResize);11 }, []);1213 return windowWidth;14}
基本上,我們使用常規(guī)的 useState
hook凄敢,我們將其指定為窗口寬度的初始值碌冶,然后在 useEffect
中添加一個(gè)監(jiān)聽器,它將在窗口調(diào)整大小時(shí)觸發(fā) handleResize
涝缝。在組件被卸載后會我們會及時(shí)知道(查看 useEffect
中的返回值)扑庞。是不是很簡單譬重?
注意: use 在 hook 中很重要。之所以使用它罐氨,是因?yàn)樗试S React 檢查你是否做了不好的事情臀规,例如從常規(guī)JS函數(shù)調(diào)用hook。
類型檢查
在支持 Flow 和 TypeScript 之前栅隐,React有自己的屬性檢查機(jī)制塔嬉。
PropTypes 檢查 React 組件接收的屬性(props)是否與我們的內(nèi)容一致。如果一致(例如:應(yīng)該是對象而不是數(shù)組)约啊,將會在控制臺中收到警告邑遏。請務(wù)必注意:PropTypes 僅在開發(fā)模式下進(jìn)行檢查,因?yàn)樗鼈儠绊懶阅懿⒃诳刂婆_中顯示上述警告恰矩。
從React 15.5開始记盒,PropTypes 被放到了不同的包里,需要單獨(dú)安裝外傅。它在名為 propTypes
(surprise)的靜態(tài)屬性中對屬性進(jìn)行聲明纪吮,可以把它與 defaultProps
結(jié)合使用,如果屬性未定義就會使用它們(undefined是唯一的情況)萎胰。 DefaultProps 與 PropTypes 無關(guān)碾盟,不過它們可以解決由于 PropTypes 而可能出現(xiàn)的一些警告。
另外兩個(gè)選擇是 Flow 和 TypeScript技竟,它們現(xiàn)在更受歡迎(特別是 TypeScript )冰肴。
TypeScript是 Microsoft 開發(fā)的 JavaScript 的類型超集,它可以在程序運(yùn)行之前檢查錯(cuò)誤榔组,并為開發(fā)工作提供卓越的自動完成功能熙尉。它還極大地改善了重構(gòu)過程。由于受到 Microsoft 的支持搓扯,它有豐富的類型語言特征检痰,也是一個(gè)相當(dāng)安全的選擇。
Flow與TypeScript不同锨推,它不是一種語言铅歼,而是 JavaScript 的靜態(tài)類型檢查器,因此它更像是 JavaScript 中的工具而并非語言换可。 Flow 背后的整個(gè)思路與 TypeScript 完全相似椎椰。它允許你添加類型,以便在運(yùn)行代碼之前杜絕可能出現(xiàn)的錯(cuò)誤沾鳄。就像 TypeScript 一樣俭识,CRA(創(chuàng)建React App)從一開始就支持 Flow。
我發(fā)現(xiàn) TypeScript 更快(幾乎是即時(shí)的)洞渔,特別是在自動完成中套媚,F(xiàn)low 似乎有點(diǎn)慢。值得注意的是磁椒,我自己用的 WebStorm 等 IDE 使用 CLI 與 Flow 集成堤瘤。但是在文件中集成可選用法似乎更容易,只需要在文件開頭添加 // @flow
就可進(jìn)行類型檢查浆熔。另外據(jù)我所知本辐,似乎 TypeScript 最終贏得了與 Flow 的戰(zhàn)斗 —— 它現(xiàn)在更受歡迎,并且一些最流行的庫正在從 Flow 轉(zhuǎn)向 TypeScript医增。
官方文檔中還提到了更多的選擇慎皱,例如 Reason(由Facebook開發(fā)并在React社區(qū)中獲得普及),Kotlin(由JetBrains開發(fā)的語言)等等叶骨。
顯然茫多,對于前端開發(fā)人員來說,最簡單的方法是使用 Flow 和 TypeScript忽刽,而不是切換到 Kotlin 或F#天揖。但是,對于正在轉(zhuǎn)型到前端的后端開發(fā)人員來說跪帝,這可能更容易入手今膊。
生產(chǎn)模式和 React 性能
對于生產(chǎn)模式,你需要做的最基本和明顯的改變是:把 DefinePlugin
切換到 “production”伞剑,并在Webpack的情況下添加UglifyJsPlugin
斑唬。在使用 CRA 的情況下,它就像使用 npm run build
(將運(yùn)行react-scripts build
)一樣簡單黎泣。請注意恕刘,Webpack 和 CRA 不是唯一的選項(xiàng),因?yàn)槟憧梢允褂闷渌麡?gòu)建工具聘裁,如 Brunch雪营。這通常包含在官方文檔中,無論是官方的 React 文檔還是特定工具的文檔衡便。要確保模式設(shè)置正確献起,你可以使用React Developer Tools【https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi】,它會告訴你正在用的那種構(gòu)建(生產(chǎn)與開發(fā))模式應(yīng)該怎么配置镣陕。上述步驟會使你的應(yīng)用在沒有來自 React 的檢查和警告的情況下運(yùn)行谴餐,并且 bundle 本身也將被最小化。
你還可以為 React 應(yīng)用做更多的事呆抑。你如何處理構(gòu)建的 JS 文件岂嗓?如果尺寸相對較小,你可以從 “bundle.js” 開始鹊碍,或者做一些類似 “vendor + bundle” 或者 “vendor + 最小化需要部件 + 在需要時(shí)導(dǎo)入東西” 之類的處理厌殉。當(dāng)你是處理一個(gè)非常大的應(yīng)用時(shí)食绿,不需要在一開始就導(dǎo)入所有內(nèi)容。請注意公罕,在主 bundle 中去 bundling 一些不會被使用的 JavaScript 代碼只會增加 bundle 包的大小器紧,并會使應(yīng)用在啟動時(shí)的加載速度變慢。
如果你計(jì)劃凍結(jié)庫的版本楼眷,并認(rèn)為它們可能長時(shí)間內(nèi)不會被更改铲汪,那么 Vendor bundles 可能很有用。此外罐柳,更大的文件更適合用 gzipping掌腰,因此從拆分獲得的好處有時(shí)可能不值得。這取決于文件大小张吉,有時(shí)你需要自己去嘗試齿梁。
代碼拆分
代碼拆分的方式比這里給出的建議多得多,但讓我們關(guān)注 CRA 和 React 本身可用的內(nèi)容芦拿∈快基本上,為了將代碼分成不同的塊蔗崎,可以使用 import()
酵幕,這可以用 Webpack 支持( import
本身是第3階段的提案,所以它還不是語言標(biāo)準(zhǔn)的一部分)缓苛。每當(dāng) Webpack 看到 import
時(shí)芳撒,它就會知道需要在這個(gè)階段開始拆分代碼,并且不能將它包含在主包中(它在import中的代碼)未桥。
現(xiàn)在我們可以將它與 React.lazy()
連接起來笔刹,它需要 import()
一個(gè)文件路徑,其中包含需要在那個(gè)地方渲染的組件冬耿。接下來舌菜,我們可以用 React.suspense()
,它會在該位置顯示不同的組件亦镶,一直到導(dǎo)入的組件全部加載完畢日月。有人可能會想,如果我要導(dǎo)入單個(gè)組件缤骨,是不是就不需要它了呢爱咬?
實(shí)際上并非如此,因?yàn)?React.lazy()
將顯示我們 import()
的組件绊起,但 import()
可能會獲取比單個(gè)組件更大的塊精拟。例如這個(gè)組件可能包含其他庫,或更多代碼,所以不只是需要一個(gè)文件 —— 它可能是綁在一起的多個(gè)文件蜂绎。最后栅表,我們可以將所有這些包裝在 ErrorBoundary
中(你可以在本文關(guān)于錯(cuò)誤邊界的那部分中找到代碼) 如果某些內(nèi)容因我們想要導(dǎo)入的組件而失敗(例如出現(xiàn)網(wǎng)絡(luò)錯(cuò)誤)荡碾,這將作為備用方案谨读。
1import ErrorBoundary from './ErrorBoundary'; 2 3const ComponentOne = React.lazy(() => import('./ComponentOne')); 4 5function MyComponent() { 6 return ( 7 <ErrorBoundary> 8 <React.Suspense fallback={<div>Loading...</div>}> 9 <ComponentOne/>10 </React.Suspense>11 </ErrorBoundary>12 );13}14
這是一個(gè)簡單的例子,但顯然你可以做得更多坛吁。你可以使用 import
和 React.lazy
進(jìn)行動態(tài)路由劃分(例如:管理員與常規(guī)用戶)。請注意铐尚,React.lazy
僅支持默認(rèn)導(dǎo)出拨脉,并且不支持服務(wù)器端呈現(xiàn)。
React 代碼性能
關(guān)于性能宣增,如果你的 React 應(yīng)用運(yùn)行緩慢玫膀,有兩種工具可以幫助你找出問題。
第一個(gè)是 Chrome Performance Tab爹脾,它會告訴你每個(gè)組件會發(fā)生什么(例如帖旨,mount,update )灵妨。有了它你應(yīng)該能夠確定哪個(gè)組件可能會出現(xiàn)性能問題解阅,然后進(jìn)行優(yōu)化。
另一個(gè)選擇是 DevTools Profiler 泌霍,它在 React 16.5+ 中可用货抄,并與 shouldComponentUpdate
配合(或PureComponent
,在本教程的第一部分中解釋)朱转,我們可以提高一些關(guān)鍵組件的性能蟹地。
顯然,對網(wǎng)絡(luò)進(jìn)行基本優(yōu)化是最佳的藤为,例如對一些事件進(jìn)行去抖動(例如怪与,滾動),對動畫保持謹(jǐn)慎(使用變換而不是通過改變高度并實(shí)現(xiàn)動畫)等等缅疟。這些問題很容易被忽略分别,特別是如果你剛剛掌握了 React。
2019年及以后的 React 現(xiàn)狀
如果要討論 React 的未來窿吩,我個(gè)人不會太在意茎杂。從我的角度來看,React 在 2019 年及以后的地位很難被撼動纫雁。
React 擁有如此強(qiáng)大的地位煌往,在一個(gè)大社區(qū)的支持下很難被廢棄。 React社區(qū)非常棒,它總是產(chǎn)生新的創(chuàng)意刽脖,核心團(tuán)隊(duì)一直在不斷努力改進(jìn) React羞海,并添加新功能和修復(fù)舊問題。 React 也得到了一家大公司的支持曲管,但許可證已經(jīng)不是問題 —— 它現(xiàn)在使用 MIT license却邓。
是的,有一些事情有望改變或改進(jìn)院水;例如腊徙,使 React 稍微小一些(提到的一個(gè)措施是刪除合成事件)或?qū)?className
重命名為 class
。當(dāng)然檬某,即使這些看似微小的變化也可能導(dǎo)致諸如影響瀏覽器兼容性等問題撬腾。就個(gè)人而言,我也想知道當(dāng) WebComponent 獲得更多人氣時(shí)會發(fā)生什么恢恼,因?yàn)樗赡軙黾右恍?React 經(jīng)常用到的東西民傻。我不相信他們會成為一個(gè)徹頭徹尾的替代者,但我相信他們可以很好地相互補(bǔ)充场斑。
至于短期漓踢,hook 剛剛被加入到 React。這可能是自 React 重寫以來發(fā)生的最大變化漏隐,因?yàn)樗鼈儗砀嗫赡苄圆⒃鰪?qiáng)更多功能組件(現(xiàn)在他們真的被大肆宣傳)喧半。
最后,正如我最近所做的那樣锁保,有React Native薯酝。對我來說,這是一項(xiàng)偉大的技術(shù)爽柒,在過去的幾年中發(fā)生了很大的變化吴菠。 React Native正在重寫它的核心,這應(yīng)該以與 React 重寫類似的方式完成(它全部是內(nèi)部的浩村,幾乎沒有任何東西應(yīng)該為開發(fā)人員改變)做葵。異步渲染成為本機(jī)和 JavaScript 之間更快更輕量級的橋梁。當(dāng)然還有更多改變心墅。
在 React 生態(tài)中有很多值得期待的東西酿矢,但 hook(以及React Native,如果有人喜歡手機(jī)應(yīng)用的話)的更新可能將會是我們在2019年所能看到的最重要的變化怎燥。