React教程:組件羊壹,Hooks和性能

翻譯:瘋狂的技術(shù)宅
原文:https://www.toptal.com/react/react-tutorial-pt2

正如 我們的React教程的第一部分 中所指出的娘扩,開始使用 React 相對(duì)容易帮掉。首先使用 Create React App(CRA)初始化一個(gè)新項(xiàng)目誊辉,然后開始開發(fā)向胡。不過遺憾的是恼蓬,隨著時(shí)間的推移,代碼可能會(huì)變得難以維護(hù)捷枯,特別是在你不熟悉 React 的情況下滚秩。組件有可能會(huì)變大,或者你可能最終得到一堆不是組件的組件淮捆,最終你可能會(huì)到處編寫重復(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)也不會(huì)到來,你將留下一堆具有大量可配置選項(xiàng)的多余通用功能/組件蟆盐。

React教程:React組件的插圖

此外承边,如果一個(gè)組件大于 2 到 3 個(gè)窗口的高度,也許值得分離(如果可能的話) —— 以后更容易閱讀石挂。

React 中的受控組件與非受控組件

在大多數(shù)應(yīng)用中博助,需要輸入和與用戶進(jìn)行某種形式的交互,允許他們輸入內(nèi)容痹愚、上傳文件富岳、選擇字段等。 React 用兩種不同的方式處理用戶交互 —— 受控非受控組件拯腮。

顧名思義窖式,受控組件的值由 React 控制,能為與用戶交互的元素提供值动壤,而不受控制的元素不獲取值屬性萝喘。多虧了這一點(diǎn),我們才能把 React 狀態(tài)作為單一的事實(shí)來源狼电,因此我們?cè)谄聊簧峡吹降呐c當(dāng)前擁有的狀態(tài)是一致的蜒灰。開發(fā)人員需要傳遞一個(gè)函數(shù),該函數(shù)用來響應(yīng)用戶與表單的交互肩碟,這將會(huì)改變它的狀態(tài)强窖。

class ControlledInput extends React.Component {
 state = {
   value: ""
 };

 onChange = (e) => this.setState({ value: e.target.value });

 render() {
   return (
     <input value={this.state.value} onChange={this.onChange}/>
   );
 }
}

在 React 的非受控組件中,我們不關(guān)心值的變化情況削祈,如果想要知道其確切的值翅溺,只需通過 ref 訪問它。

class UncontrolledInput extends React.Component {
 input = React.createRef();

 getValue = () => {
   console.log(this.input.current.value);
 };

 render() {
   return (
     <input ref={this.input}/>
   );
 }
}

那么應(yīng)該怎么選擇呢髓抑?在大數(shù)情況下用受控組件是可行的咙崎,不過也有一些例外。例如使用非受控制組件的一種情況是 file 類型輸入吨拍,因?yàn)樗闹凳侵蛔x的褪猛,不能在編碼中去設(shè)置(需要用戶交互)。另外我發(fā)現(xiàn)受控組件更容易理解和于使用羹饰。對(duì)受控組件的驗(yàn)證是基于重新渲染的伊滋,狀態(tài)可以更改碳却,并且可以很輕松的顯示輸入中存在的問題(例如格式錯(cuò)誤或者輸入為空)。

Refs

在前面我們提到過 refs笑旺,這是一個(gè)特殊功能昼浦,可以在類組件中使用,直到 16.8 中出現(xiàn)了 hooks筒主。

refs 可以通過引用讓開發(fā)人員訪問 React 組件或DOM元素(取決于我們附加 ref 的類型)关噪。最好僅在必須的場(chǎng)景中使用它們,因?yàn)樗鼈儠?huì)使代碼難以閱讀乌妙,并打破從上到下的數(shù)據(jù)流使兔。然而,有些情況下它們是必要的冠胯,特別是在DOM元素上(例如:用編碼方式改變焦點(diǎn))火诸。附加到 React 組件元素時(shí)锦针,你可以自由使用所引用的組件中的方法荠察。不過還是應(yīng)該避免這種做法,因?yàn)橛懈玫姆椒▉硖幚硭ɡ缒嗡眩嵘隣顟B(tài)并將功能移動(dòng)到父組件)悉盆。

refs 還可以做到:

  • 使用字符串字面量(歷史遺留的,應(yīng)該避免)馋吗,
  • 使用在 ref 屬性中設(shè)置的回調(diào)函數(shù)焕盟,
  • 通過創(chuàng)建 ref 作為 React.createRef() ,并將其綁定到類屬性宏粤,并通過它去訪問(請(qǐng)注意脚翘,在 componentDidMount 生命周期中將提供引用)。

沒有傳遞引用的一種情況是當(dāng)在組件上使用高階組件時(shí) —— 原因是可以理解的绍哎,因?yàn)?ref 不是 prop(類似于 key)所以它沒有被傳遞下來来农,并且它將引用 HOC 而不是被它包裹的組件。在這種情況下崇堰,我們可以使用React.forwardRef沃于,它把 props 和 ref 作為參數(shù),然后可以將其分配給 prop 并傳遞給我們想要訪問的組件海诲。

function withNewReference(Component) {
 class Hoc extends React.Component {
   render() {
     const {forwardedRef, ...props} = this.props;

     return <Component ref={forwardedRef} {...props}/>;
   }
 }

 return React.forwardRef((props, ref) => {
   return <Hoc {...props} forwardedRef={ref} />;
 });
}

錯(cuò)誤邊界

事情越復(fù)雜繁莹,出現(xiàn)問題的概率就越高。這就是為什么 React 中會(huì)有錯(cuò)誤邊界特幔。那他們是怎么工作的呢咨演?

如果出現(xiàn)問題并且沒有錯(cuò)誤邊界作為其父級(jí),則會(huì)導(dǎo)致整個(gè)React 應(yīng)用失敗蚯斯。不顯示信息比誤導(dǎo)用戶并顯示錯(cuò)誤信息要好薄风,但這并不意味著你應(yīng)該放任整個(gè)應(yīng)用崩潰并顯示白屏零院。通過錯(cuò)誤邊界,可以得到更多的靈活性村刨。你可以在整個(gè)應(yīng)用程序中使用并顯示一個(gè)錯(cuò)誤消息告抄,或者在某些小部件中使用它但是不顯示,或者顯示少量信息來代替這些小部件嵌牺。

請(qǐng)記住打洼,它僅涉及聲明性代碼的問題,而不是你為了處理某些事件或者調(diào)用而編寫的命令式代碼逆粹。對(duì)于這些情況募疮,你仍應(yīng)使用常規(guī)的 try/catch 方法。

在錯(cuò)誤邊界也可以將信息發(fā)送到你使用的 Error Logger (在 componentDidCatch 生命周期方法中)僻弹。

class ErrorBoundary extends React.Component {
  state = { hasError: false };

  static getDerivedStateFromError(error) {
    return { hasError: true };
  }

  componentDidCatch(error, info) {
    logToErrorLogger(error, info);
  }

  render() {
    if (this.state.hasError) {
      return <div>Help, something went wrong.</div>;
    }

    return this.props.children; 
  }
}

高階組件

高階組件(HOC)經(jīng)常在 React 中被提及阿浓,這是一種非常流行的模式,你可能會(huì)用到它(或者已經(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)方法不會(huì)被自動(dòng)復(fù)制,所以如果你想在新創(chuàng)建的 HOC 中使用一些靜態(tài)方法绿渣,需要自己去復(fù)制它們朝群。
  • 涉及到的 Refs 不會(huì)被傳遞,所以使用前面提到的 React.forwardRef 來解決這些問題中符。
export function importantHoc() {
   return (Component) => class extends React.Component {
       importantFunction = () => {
           console.log("Very Important Function");
       };

       render() {
           return (
               <Component
                   {...this.props}
                   importantFunction={this.importantFunction}
               />
           );
       }
   };
}

樣式

樣式不一定與 React 本身有關(guān)姜胖,但出于各種原因還是值得一提的。

首先淀散,常規(guī) CSS/內(nèi)聯(lián)樣式在這里能夠正常應(yīng)用右莱,你只需在 className 屬性中添加 CSS 中的類名,它就能正常工作档插。內(nèi)聯(lián)樣式與常規(guī) HTML 樣式略有不同慢蜓。樣式屬性也是使用駝峰命名法,因此 border-radius 會(huì)變成 borderRadius 郭膛。

React 似乎推廣了一些不僅在 React 中變得普遍的解決方案晨抡,例如最近集成在 CRA 中的 CSS 模塊,你可以在其中簡單地導(dǎo)入 name.modules.css 并用其屬性來調(diào)整組件的樣式(某些IDE(例如WebStorm)也具有自動(dòng)完成功能则剃,能告訴你可用的名稱耘柱。

在 React 中另一個(gè)流行的解決方案是 CSS-in-JS(例如,emotion 庫)忍级。再說一點(diǎn)帆谍,CSS 模塊和 emotion(或者一般來說是CSS-in-JS)對(duì) React 沒有限制

React 中的 Hooks

自重寫以來轴咱,**Hooks **很可能是 React 最受熱切期待的補(bǔ)充。這個(gè)產(chǎn)品是否能不負(fù)眾望烈涮?從我的角度來看朴肺,是的,因?yàn)樗_實(shí)是一個(gè)很棒的功能坚洽。它們本質(zhì)上是帶來了新的體驗(yàn)戈稿,例如:

  • 允許刪除許多 class 組件,這些組件我們僅僅是使用而不歸我們擁有讶舰,例如本地狀態(tài)或 ref鞍盗,所以組件的代碼看上去更容易閱讀。
  • 可以讓你用更少的代碼來獲得相同的效果跳昼。
  • 使函數(shù)更容易理解和測(cè)試般甲,例如:用 react-testing-library
  • 也可以攜帶參數(shù)鹅颊,一個(gè) hook 返回的結(jié)果可以很容易地被另一個(gè) hook 使用(例如敷存,useEffect 中的 setStateuseState 使用)。
  • 比類更好地縮小方式堪伍,這對(duì)于 minifiers 來說往往更成問題锚烦。
  • 可能會(huì)刪除 HOC 并在你的應(yīng)用中渲染 props 觅闽,盡管 hook 被設(shè)計(jì)用于解決其他問題,但仍會(huì)引入新問題涮俄。
  • 能夠被熟練的React開發(fā)人員定制

默認(rèn)的 React hook 很少蛉拙。其中三個(gè)基本的hook是 useStateuseEffectuseContext彻亲。還有一些其它的刘离,例如 useRefuseMemo,不過現(xiàn)在我們把重點(diǎn)放在基礎(chǔ)知識(shí)上睹栖。

先看一下 useState硫惕,讓我們用它來創(chuàng)建一個(gè)簡單的計(jì)數(shù)器的。它是如何工作的野来?基本上整個(gè)結(jié)構(gòu)非常簡單:

export function Counter() {
 const [counter, setCounter] = React.useState(0);

 return (
   <div>
     {counter}
     <button onClick={() => setCounter(counter + 1)}>+</button>
   </div>
 );
};

它用 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ù),格式如下:

<button onClick={() => setCounter(prevCounter => prevCounter + 1)}>+</button>
<button onClick={() => setCounter(prevCounter => prevCounter - 1)}>-</button>

與執(zhí)行淺合并的this.setState 類組件不同强重,設(shè)置函數(shù)(在我們的例子中為 setCounter )會(huì)覆蓋整個(gè)狀態(tài)绞呈。

另外,initialState 也可以是一個(gè)函數(shù)间景,而不僅僅是一個(gè)普通的值佃声。這有其自身的好處,因?yàn)樵摵瘮?shù)將會(huì)只在組件的初始渲染期間運(yùn)行拱燃,之后將不再被調(diào)用秉溉。

const [counter, setCounter] = useState(() =>  calculateComplexInitialValue());

最后,如果我們要使用 setCounter 與在當(dāng)前狀態(tài)(counter)的同一時(shí)刻完全相同的值,那么組件 將不會(huì) 重新渲染召嘶。

另一方面父晶,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ù)組蜕着。

const fetchApi = async () => {
 const value = await fetch("https://jsonplaceholder.typicode.com/todos/1");
 console.log(await value.json());
};

export function Counter() {
 const [counter, setCounter] = useState(0);
 useEffect(() => {
   fetchApi();
 }, []);


 return (
   <div>
     {counter}
     <button onClick={() => setCounter(prevCounter => prevCounter + 1)}>+</button>
     <button onClick={() => setCounter(prevCounter => prevCounter - 1)}>-</button>
   </div>
 );
};

由于把空數(shù)組作為第二個(gè)參數(shù)谋竖,所以上面的代碼只運(yùn)行一次。在這種情況下它類似于 componentDidMount承匣,但稍后會(huì)觸發(fā)它蓖乘。如果你想在瀏覽器處理之前調(diào)用一個(gè)類似的 hook,可以用 useLayoutEffect韧骗,但這些更新將會(huì)被同步應(yīng)用嘉抒,這一點(diǎn)與 useEffect 不同。

useContext 似乎是最容易理解的袍暴,因?yàn)槲覀兲峁┝讼胍L問的上下文(由 createContext 函數(shù)返回的對(duì)象提供)些侍,而它為我們提供了該上下文的值。

const context = useContext(Context);

最后容诬,要編寫自己的hook娩梨,你可以像這樣寫:

function useWindowWidth() {
 let [windowWidth, setWindowWidth] = useState(window.innerWidth);

 function handleResize() {
   setWindowWidth(window.innerWidth);
 }

 useEffect(() => {
   window.addEventListener('resize', handleResize);
   return () => window.removeEventListener('resize', handleResize);
 }, []);

 return windowWidth;
}

基本上,我們使用常規(guī)的 useState hook览徒,我們將其指定為窗口寬度的初始值,然后在 useEffect 中添加一個(gè)監(jiān)聽器颂龙,它將在窗口調(diào)整大小時(shí)觸發(fā) handleResize习蓬。在組件被卸載后會(huì)我們會(huì)及時(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)該是對(duì)象而不是數(shù)組),將會(huì)在控制臺(tái)中收到警告荣挨。請(qǐng)務(wù)必注意:PropTypes 僅在開發(fā)模式下進(jìn)行檢查,因?yàn)樗鼈儠?huì)影響性能并在控制臺(tái)中顯示上述警告勾给。

從React 15.5開始恍涂,PropTypes 被放到了不同的包里,需要單獨(dú)安裝足丢。它在名為 propTypes(surprise)的靜態(tài)屬性中對(duì)屬性進(jìn)行聲明粱腻,可以把它與 defaultProps 結(jié)合使用,如果屬性未定義就會(huì)使用它們(undefined是唯一的情況)斩跌。 DefaultProps 與 PropTypes 無關(guān)绍些,不過它們可以解決由于 PropTypes 而可能出現(xiàn)的一些警告。

另外兩個(gè)選擇是 Flow 和 TypeScript耀鸦,它們現(xiàn)在更受歡迎(特別是 TypeScript )柬批。

  • TypeScript是 Microsoft 開發(fā)的 JavaScript 的類型超集,它可以在程序運(yùn)行之前檢查錯(cuò)誤揭糕,并為開發(fā)工作提供卓越的自動(dòng)完成功能萝快。它還極大地改善了重構(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í)的)谆刨,特別是在自動(dòng)完成中塘娶,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ā)的語言)等等。

顯然击敌,對(duì)于前端開發(fā)人員來說介返,最簡單的方法是使用 Flow 和 TypeScript,而不是切換到 Kotlin 或F#沃斤。但是圣蝎,對(duì)于正在轉(zhuǎn)型到前端的后端開發(fā)人員來說,這可能更容易入手衡瓶。

生產(chǎn)模式和 React 性能

對(duì)于生產(chǎn)模式徘公,你需要做的最基本和明顯的改變是:把 DefinePlugin 切換到 “production”,并在Webpack的情況下添加UglifyJsPlugin哮针。在使用 CRA 的情況下关面,它就像使用 npm run build(將運(yùn)行react-scripts build)一樣簡單。請(qǐng)注意十厢,Webpack 和 CRA 不是唯一的選項(xiàng)等太,因?yàn)槟憧梢允褂闷渌麡?gòu)建工具,如 Brunch蛮放。這通常包含在官方文檔中缩抡,無論是官方的 React 文檔還是特定工具的文檔。要確保模式設(shè)置正確包颁,你可以使用React Developer Tools瞻想,它會(huì)告訴你正在用的那種構(gòu)建(生產(chǎn)與開發(fā))模式應(yīng)該怎么配置。上述步驟會(huì)使你的應(yīng)用在沒有來自 React 的檢查和警告的情況下運(yùn)行娩嚼,并且 bundle 本身也將被最小化蘑险。

你還可以為 React 應(yīng)用做更多的事。你如何處理構(gòu)建的 JS 文件岳悟?如果尺寸相對(duì)較小佃迄,你可以從 “bundle.js” 開始,或者做一些類似 “vendor + bundle” 或者 “vendor + 最小化需要部件 + 在需要時(shí)導(dǎo)入東西” 之類的處理贵少。當(dāng)你是處理一個(gè)非常大的應(yīng)用時(shí)和屎,不需要在一開始就導(dǎo)入所有內(nèi)容。請(qǐng)注意春瞬,在主 bundle 中去 bundling 一些不會(huì)被使用的 JavaScript 代碼只會(huì)增加 bundle 包的大小,并會(huì)使應(yīng)用在啟動(dòng)時(shí)的加載速度變慢套啤。

如果你計(jì)劃凍結(jié)庫的版本宽气,并認(rèn)為它們可能長時(shí)間內(nèi)不會(huì)被更改随常,那么 Vendor bundles 可能很有用。此外萄涯,更大的文件更適合用 gzipping绪氛,因此從拆分獲得的好處有時(shí)可能不值得。這取決于文件大小涝影,有時(shí)你需要自己去嘗試枣察。

代碼拆分

代碼拆分的方式比這里給出的建議多得多,但讓我們關(guān)注 CRA 和 React 本身可用的內(nèi)容燃逻⌒蚰浚基本上,為了將代碼分成不同的塊伯襟,可以使用 import()猿涨,這可以用 Webpack 支持( import本身是第3階段的提案,所以它還不是語言標(biāo)準(zhǔn)的一部分)姆怪。每當(dāng) Webpack 看到 import 時(shí)叛赚,它就會(huì)知道需要在這個(gè)階段開始拆分代碼,并且不能將它包含在主包中(它在import中的代碼)稽揭。

現(xiàn)在我們可以將它與 React.lazy() 連接起來俺附,它需要 import() 一個(gè)文件路徑,其中包含需要在那個(gè)地方渲染的組件溪掀。接下來事镣,我們可以用 React.suspense(),它會(huì)在該位置顯示不同的組件膨桥,一直到導(dǎo)入的組件全部加載完畢蛮浑。有人可能會(huì)想,如果我要導(dǎo)入單個(gè)組件只嚣,是不是就不需要它了呢沮稚?

實(shí)際上并非如此,因?yàn)?React.lazy() 將顯示我們 import() 的組件册舞,但 import() 可能會(huì)獲取比單個(gè)組件更大的塊蕴掏。例如這個(gè)組件可能包含其他庫,或更多代碼调鲸,所以不只是需要一個(gè)文件 —— 它可能是綁在一起的多個(gè)文件盛杰。最后,我們可以將所有這些包裝在 ErrorBoundary(你可以在本文關(guān)于錯(cuò)誤邊界的那部分中找到代碼) 如果某些內(nèi)容因我們想要導(dǎo)入的組件而失斆晔(例如出現(xiàn)網(wǎng)絡(luò)錯(cuò)誤)即供,這將作為備用方案。

import ErrorBoundary from './ErrorBoundary';

const ComponentOne = React.lazy(() => import('./ComponentOne'));

function MyComponent() {
   return (
       <ErrorBoundary>
           <React.Suspense fallback={<div>Loading...</div>}>
               <ComponentOne/>
           </React.Suspense>
       </ErrorBoundary>
   );
}

這是一個(gè)簡單的例子于微,但顯然你可以做得更多逗嫡。你可以使用 importReact.lazy 進(jìn)行動(dòng)態(tài)路由劃分(例如:管理員與常規(guī)用戶)青自。請(qǐng)注意,React.lazy 僅支持默認(rèn)導(dǎo)出驱证,并且不支持服務(wù)器端呈現(xiàn)延窜。

React 代碼性能

關(guān)于性能,如果你的 React 應(yīng)用運(yùn)行緩慢抹锄,有兩種工具可以幫助你找出問題逆瑞。

第一個(gè)是 Chrome Performance Tab,它會(huì)告訴你每個(gè)組件會(huì)發(fā)生什么(例如伙单,mount获高,update )。有了它你應(yīng)該能夠確定哪個(gè)組件可能會(huì)出現(xiàn)性能問題车份,然后進(jìn)行優(yōu)化谋减。

另一種選擇是 DevTools Profiler ,它在 React 16.5+ 中可用扫沼,并與 shouldComponentUpdate 配合(或PureComponent出爹,在本教程的第一部分中解釋),我們可以提高一些關(guān)鍵組件的性能缎除。

顯然严就,對(duì)網(wǎng)絡(luò)進(jìn)行基本優(yōu)化是最佳的,例如對(duì)一些事件進(jìn)行去抖動(dòng)(例如器罐,滾動(dòng))梢为,對(duì)動(dòng)畫保持謹(jǐn)慎(使用變換而不是通過改變高度并實(shí)現(xiàn)動(dòng)畫)等等。這些問題很容易被忽略轰坊,特別是如果你剛剛掌握了 React铸董。

2019年及以后的 React 現(xiàn)狀

如果要討論 React 的未來,我個(gè)人不會(huì)太在意肴沫。從我的角度來看粟害,React 在 2019 年及以后的地位很難被撼動(dòng)。

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í)會(huì)發(fā)生什么栋艳,因?yàn)樗赡軙?huì)增加一些 React 經(jīng)常用到的東西恰聘。我不相信他們會(huì)成為一個(gè)徹頭徹尾的替代者,但我相信他們可以很好地相互補(bǔ)充吸占。

至于短期晴叨,hook 剛剛被加入到 React。這可能是自 React 重寫以來發(fā)生的最大變化矾屯,因?yàn)樗鼈儗砀嗫赡苄圆⒃鰪?qiáng)更多功能組件(現(xiàn)在他們真的被大肆宣傳)兼蕊。

最后,正如我最近所說的那樣件蚕,有React Native孙技。對(duì)我來說,這是一項(xiàng)偉大的技術(shù)排作,在過去的幾年中發(fā)生了很大的變化牵啦。 React Native正在重寫它的核心,這應(yīng)該以與 React 重寫類似的方式完成(它全部是內(nèi)部的妄痪,幾乎沒有任何東西應(yīng)該為開發(fā)人員改變)哈雏。異步渲染成為本機(jī)和 JavaScript 之間更快更輕量級(jí)的橋梁。當(dāng)然還有更多改變衫生。

在 React 生態(tài)中有很多值得期待的東西裳瘪,但 hook(以及React Native,如果有人喜歡手機(jī)應(yīng)用的話)的更新可能將會(huì)是我們?cè)?019年所能看到的最重要的變化罪针。


關(guān)注微信公眾號(hào)彭羹,每天推送前端趨勢(shì)和技術(shù)文章

微信掃一掃關(guān)注公眾號(hào)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市站故,隨后出現(xiàn)的幾起案子皆怕,更是在濱河造成了極大的恐慌,老刑警劉巖西篓,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件愈腾,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡岂津,警方通過查閱死者的電腦和手機(jī)虱黄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吮成,“玉大人橱乱,你說我怎么就攤上這事辜梳。” “怎么了泳叠?”我有些...
    開封第一講書人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵作瞄,是天一觀的道長。 經(jīng)常有香客問我危纫,道長宗挥,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任种蝶,我火速辦了婚禮契耿,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘螃征。我一直安慰自己搪桂,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開白布盯滚。 她就那樣靜靜地躺著踢械,像睡著了一般。 火紅的嫁衣襯著肌膚如雪淌山。 梳的紋絲不亂的頭發(fā)上裸燎,一...
    開封第一講書人閱讀 51,146評(píng)論 1 297
  • 那天,我揣著相機(jī)與錄音泼疑,去河邊找鬼德绿。 笑死,一個(gè)胖子當(dāng)著我的面吹牛退渗,可吹牛的內(nèi)容都是我干的移稳。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼会油,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼个粱!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起翻翩,我...
    開封第一講書人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤都许,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后嫂冻,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體胶征,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年桨仿,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了睛低。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖钱雷,靈堂內(nèi)的尸體忽然破棺而出骂铁,到底是詐尸還是另有隱情,我是刑警寧澤罩抗,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布拉庵,位于F島的核電站,受9級(jí)特大地震影響澄暮,放射性物質(zhì)發(fā)生泄漏名段。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一泣懊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧麻惶,春花似錦馍刮、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至警没,卻和暖如春匈辱,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背杀迹。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來泰國打工亡脸, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人树酪。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓浅碾,卻偏偏與公主長得像,于是被迫代替她去往敵國和親续语。 傳聞我的和親對(duì)象是個(gè)殘疾皇子垂谢,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353

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

  • 秋思 萌萌 秋風(fēng)起,秋葉黃 秋意纏綿處疮茄,秋思晝夜長 秋雨落滥朱,秋水涼 秋愁落寞隨塵歸,秋夜冷月光
    棲梧軒開心果閱讀 481評(píng)論 0 1
  • 最近在學(xué)習(xí)CSS動(dòng)畫相關(guān)的知識(shí)力试,于是連帶著把會(huì)用到的一些知識(shí)點(diǎn)進(jìn)行了一些整理徙邻。在此,做一下總結(jié)懂版。 Transfor...
    SCQ000閱讀 7,108評(píng)論 0 51
  • 回老家參加高中同學(xué)兼前男友的婚禮的學(xué)霸江舒同學(xué)偶遇了當(dāng)年高中時(shí)的校草 1 校草:你好鹃栽,我暗戀你十年了 學(xué)霸江舒:你...
    江江不入海閱讀 376評(píng)論 0 1