翻譯:瘋狂的技術宅
原文: https://www.toptal.com/react/...
本文首發微信公衆號:jingchengyideng
歡迎關注,天天都給你推送新鮮的前端技術文章html
前端和 JavaScript 是一個奇怪的世界。大量不斷推出的新技術的同時,也在被不須要它們的人嘲笑,每每不少人都會這樣作。咱們有時會對不斷涌現的信息、庫和討論感到不知所措,總但願能有一些穩定的東西,就像能讓咱們能夠休整一段時間的避風港。最近 React 彷佛有變成 JavaScript 演變海洋中溫暖港灣的趨勢。前端
正是考慮到這一點,咱們決定製做這個 React 系列教程,展現它的功能,並看看它與 Angular 和 VueJS 相比有什麼特色。vue
固然 React 並非惟一的選擇,但目前它是最受歡迎、最穩定、最具備創新性的解決方案之一,雖然它仍然在不斷升級,但更多的是在改進,而不是增長功能。react
React 是一個視圖庫,能夠一直追溯到2011年,當時它的第一個原型名爲 FaxJs,並出如今 Facebook 上,React 是由 Jordan Walke(他也是上述原型的做者)於2013年5月29日在 JSConfUS 推出的,並於2013年7月2日在 GitHub 上公開發布。git
在2014年,當開始擴大社區並推廣 React 時,它受到持續歡迎。然而從個人角度來看,2015年是大型公司(例如 Airbnb 和 Netflix )開始喜歡並採用 React 的里程碑年。此外,當年還出現了React Native。 React Native背後的想法並非什麼全新的東西,不過看起來頗有趣,尤爲是由於它獲得了 Facebook 的支持。程序員
另外一個重大變化是 Redux,一個 Flux 實現。這使狀態管理方式更加簡單友好,使其成爲迄今爲止最成功的實現。github
從其出現一直到如今,還有不少其餘的東西供咱們使用,包括 React tools,重寫了核心算法;Fiber 用於語義轉換版本控制等等。到了今天,咱們處於 v16.6.3,幾周後可能就會發布支持 Hooks 的新版本(它應該在 16.7.0 獲得支持,但因爲對 React.lazy 作了一些修復,就先發布了一個版本)。React 因爲其名氣和穩定性得到了普遍好評。面試
好吧,若是你身爲前端開發人員可是歷來都沒有據說過,那麼我就要說聲「恭喜你」,由於這是一個了不得的壯舉。算法
開個玩笑而已。React 是一個聲明式的基於組件的視圖庫,能夠幫助你構建 UI。它是一個庫而不是一個框架,雖然最初不少人把它描述爲後者。npm
顯然,若是咱們要把 Redux 和 React Router 等添加到 React,它就擁有了製做常規單頁應用程序所需的全部東西,這可能這就是它有時被錯誤地描述爲框架而不是庫的緣由 。若是必定要這樣認爲的話,將該環境的全部組件放在一塊兒,術語「框架」可能有點適合它,但就其自己而言,React 僅僅是一個庫。
不要再糾結改怎麼對其分類了,先關注 React 有什麼獨特之處,一些以前沒有注意到的東西。首先,當你第一次看到 React 時,就會想到 JSX,由於這是你看到代碼時的第一個感覺。 JSX是一種 JavaScript 語法擴展,有點相似於 HTML/XML。說到 React 和 JSX,它們與 HTML 有一些區別,例如,React 中的類是 className
,沒有tabindex 可是有 tabIndex
,樣式接受具備駝峯命名的屬性的 JavaScript 對象,依此類推。
有一些細微的差異,可是任何人都應該當即接受它們。事件處理是經過例如 onChange
和 onClick
屬性實現的,這些屬性能夠用來附加一些函數來處理事件。此外,之後的組件能夠經過使用 props 自由重用和自定義,所以沒有理由屢次編寫相同的代碼。
import React, { Component } from 'react'; export default class App extends Component { render() { return ( <div>Hello World, {this.props.name}</div> ); } }
可是實際上 JSX 在 React 中並非很是必要的。你能夠編寫常規函數來建立元素,而無需使用JSX。上面的代碼能夠像下面這樣去用。
import React, { Component } from 'react'; export default class App extends Component { render() { return React.createElement( 'div', null, 'Hello World, ', this.props.name ); } }
很顯然我並非建議你用這樣的語法,儘管有些狀況下它有可能會派上用場(例如你想要引入一個很是小的東西可是又不想更改構建環境)。
實際上我展現上述代碼還有另外一個緣由。一般,開發人員不理解咱們爲何須要執行如下操做:
import React from 'react';
代碼片斷應該是可以自解釋的。即便咱們正在提取 Component
,仍然須要 React,由於 Babel 在 JSX 之上轉換爲 React.createElement
。因此若是咱們不導入 React 就會失效。前面我提到了 Babel,這是一個工具,能夠幫助咱們預覽那些還沒有在 JavaScript 中(更確切地說是在瀏覽器中)支持的東西,或者以某種方式對 JavaScript 進行擴展(或者相似於 TypeScript,Babel 從 Babel 7 開始支持的不一樣語言)。感謝Babel:
JSX 將被轉化爲成瀏覽器能夠理解的代碼。
簡而言之,在 JavaScript 中,就是今天的代碼明天仍然能用;這可能須要爲此專門再寫一篇文章。值得一提的是,React 的導入也能夠被一些其餘技術繞過(好比經過 Webpack 引入 ProvidePlugin 等),可是因爲篇幅有限,咱們將避免使用這種方式,並假設用戶將使用 Create React App( CRA)(稍後將提到有關此工具的更多信息)。
另外一點比 JSX 自己更重要,那就是 React 基於虛擬 DOM。簡而言之,虛擬 DOM 是用 JavaScript 編寫的在內存中的理想樹結構,稍後咱們會把它與真實 DOM 進行比較。
我很不喜歡對庫進行比較,特別是當咱們被迫把梨和蘋果放在一塊兒進行比較時。
所以,我將嘗試使用一系列簡短的問題和答案將 React 與 Angular 和 Vue 進行比較。這種比較與技術相關,而不是主觀的做出 「X比Y更好,由於它使用 JSX 而不是模板。」 這種出於我的偏好的對比。另外在速度和內存分配等方面 React 與其主要競爭對手(Angular 和 Vue 都能想獲得)很是類似,有一篇關於這個問題的文章很不錯,但請記住這一點:絕大多數程序並不會作這種處理上萬行數據的事。所以,這些結果也是純粹的速度實驗。實際上你也不會把這放在首位。
那麼讓咱們來看看關於 React 的問題以及它與競爭對手的比較:
我想擁有更多的工做機會。 React 到底有多受歡迎?
嗯,這很容易回答 —— 選擇 React。實際上,我會說 React 的工做機會大約其它的 6 到 10 倍(可能出入比較大,在一些大網站是 50 倍,也有些網站是 6 倍),是 Vue 的 2 到 4倍,比 Angular 更多。對 React experts 的需求很大,可是爲何 Vue 在 GitHub 上很是受歡迎(實際上它得到了比 React 更多的star)卻沒有更多的職位空缺?這點我不知道。【譯者注:做者是美國人,這裏指的是美國的就業市場】
我想要一個很大的社區,還有大量的庫,可以快速解決可能出現的問題。
選 React,不要再猶豫了。
它是否容易使用,開發過程是否使人愉快?
2018年和2017年的 JS 狀態報告顯示,React 和 Vue 都享有良好的聲譽,大多數開發人員表示會再次使用。另外一方面Angular 有一種趨勢,每一年都會有愈來愈多的人說不會再次使用它。
我想建立一個新的單面應用,但我不想額外去找這種支持庫。
我認爲這大概是 Angular 值得選擇的惟一緣由。
我不是大公司。可是但願儘量獨立,應該選擇哪一個?
Vue —— 它是咱們三巨頭中惟一獨立的一個。 ( Facebook 支持 React,而 Google 支持 Angular。)
上手最簡單和最快的學習曲線?
Vue/React。在這裏我更傾向於 Vue,但這只是我我的的意見。至於爲何?由於你不須要懂 JSX(它是可選的),它基本上只是 HTML + CSS + JavaScript。
目前上手 React 最簡單方法是使用 CRA,這是一個爲你建立項目的 CLI 工具,可幫助你避免配置 Webpack / Babel 等環境。你只須要依賴默的認配置方式,並隨着時間的推移更新包含在內的內容。多虧了這一點,你無需關心某些關鍵庫的主要更新。
固然,稍後,你能夠經過運行 npm run eject
來「彈出」本身並本身處理每一個細節。這種方法有其自身的優勢,由於你能夠增長原來不可用的東西(例如裝飾器)來加強你的應用,但它也多是使人頭疼的問題,由於它須要花費更多的時間去配置許多額外的文件。
因此,首先要作的是:
npx create-react-app {app-name}
而後 npm run start
就完成了。
咱們應該先解釋這些組件的不一樣之處。基本上每一個組件能夠是 function 或 class。它們之間的主要區別在於,類組件有函數組件中沒有的一些功能:它們有 state 並使用 refs、生命週期等。從 v16.7 開始咱們可使用 hooks,所以可使用 hooks 來進行 state 和 refs。
類組件有兩種類型:Component
和 PureComponent
。它們惟一的區別是 PureComponent
能夠對 props 和 state 進行淺層比較 —— 這在你不想「浪費」渲染資源的狀況下有獨到的好處,一個組件及其子組件剛好在渲染後處於相同狀態。不過它只有一個淺層比較;若是你想實現本身的比較操做(假如你傳遞的是複雜的 props),只須要用 Component
並覆蓋 shouldComponentUpdate
(默認狀況下返回true)。從 16.6 + 開始,在函數組件中也能夠用相似的東西 —— 全靠 React.memo
這個更高階的組件,在默認狀況下表現得像 PureComponent
(淺層比較),在你進行自定義的 props 比較時它還須要第二個參數。
通常來講若是你能用函數組件(假設你不須要類功能)那麼就用它。不過從 16.7.0 開始,因爲生命週期方法,只能用類組件。可是我認爲函數組件更透明,更容易推理和理解。
Constructor(props)
可選,CRA 使其變得受歡迎,默認包含 JavaScript 的類字段聲明。聲明是否經過類中的箭頭函數去綁定方法是沒有意義的。相似的狀態也能夠初始化爲類屬性。
componentDidMount()
setState
(可是它會使組件從新渲染)。componentWillUnmount()
setState
,由於它沒有意義,由於組件將會被卸載(而且你會獲得一個警告)。componentDidUpdate(prevProps, prevState, snapshot)
getSnapshotBeforeUpdate
時纔會出現的快照 )。shouldComponentUpdate
返回true時纔會執行。If you use setState
here, you should guard it or you will land in an infinite loop.
setState
,應該保護它,不然將會陷入無限循環。shouldComponentUpdate(nextProps, nextState)
若是返回 false,則不會調用渲染器。
PureComponent
。getSnapshotBeforeUpdate()
componentDidUpdate
中重用,用來恢復滾動的位置。componentDidCatch(error, info)
setState
,但在之後的版本中,將會在靜態方法getDerivedStateFromError(error)
中被刪除,它將經過返回一個值來更新狀態。還有兩種靜態方法,在其餘的段落中提到過
static getDerivedStateFromError(error)
static getSnapshotBeforeUpdate(props, state)
注意,目前還有更多可用的方法,但它們可能會在 React 17.0 中被刪除,因此就不在這裏沒有提起了。
咱們先從 Props 開始,由於它更容易解釋。Props 是傳給組件的屬性,之後能夠在組件顯示信息或業務邏輯時重用它 。
import React, { Component } from 'react'; export default class App extends Component { render() { return ( <div> <HelloWorld name="Someone :)"/> </div> ); } } const HelloWorld = (props) => <div>Hello {props.name}</div>
在上面的例子中,name
是一個 prop。prop 是隻讀元素,不能直接在子組件中更改。不少人有一種不太好的習慣,那就是把 prop 複製到 state ,而後再對 state 進行操做。固然有時候你但願執行相似 「在提交以後去更新父組件的初始狀態」 這樣的操做,但這種狀況很是少見 —— 在這種狀況下,更新初始狀態可能有意義。另外不只能夠給子組件傳遞字符串這樣的 prop ,還能夠傳遞數字、對象、函數等。
prop 還有一個更有用的東西叫作 defaultProps
,這是一個靜態字段,它能夠告訴你組件的默認 prop 是什麼(好比當它們沒有傳遞給組件時)。
在「狀態提高」的狀況下,其中一個組件(父組件)具備稍後由其子組件重用的狀態(例如,一個子組件用來顯示而另外一個用來編輯),那麼咱們須要將該功能從父組件傳遞給子組件。 它容許咱們更新父級的本地狀態。
另外一方面,狀態是一個能夠修改的本地狀態,可是經過 this.setState
間接修改。若是直接去改變狀態,組件將不會感知到,更不會由於狀態的改變而從新渲染。
SetState 是一種更改本地狀態對象的方法(經過執行淺層合併),以後組件經過從新渲染本身來響應它。請注意,在使用 setState
以後,this.state
屬性不會當即對更改(它具備異步性質)做出反應,由於優化的緣由,可能會將 setState
的幾個實例一塊兒進行批處理。調用它的方式有好幾種,其中一種方式容許咱們在對狀態進行更新可以後當即對組件執行某些操做:
setState({value: ‘5’})
setState((state, props) => ({value: state.name + 「‘s」}))
setState([object / function like above], () => {})
—— 這個表單容許咱們附加 callback
,當 state 顯示咱們想要的數據時被調用(在第一個參數)。import React, { Component } from 'react'; export default class App extends Component { state = { name: 'Someone :)' } onClick = () => this.setState({ name: 'You' }) render() { return ( <div> <HelloWorld name={this.state.name} onClick={this.onClick}/> </div> ); } } const HelloWorld = (props) => <div onClick={props.onClick}>Hello {props.name}</div>
React 最近穩定的 Context API(已經在 React 中存在了至關長的時間,儘管被 Redux 等一些最受歡迎的庫普遍使用,倒是一個實驗性功能)有助於咱們解決一個問題:Props drilling。簡而言之 Props drilling 是在結構中深刻傳遞 props 的一種方式 —— 例如,它能夠是組件的某種主題、針對特定語言的本地化、用戶信息等。在 Context出現以前(或者更確切地說,在它變成非實驗功能以前),它是經過遞歸方式從父級一直傳遞到到子級的最後一級的來進行鑽取的(顯然還有能夠解決這個問題的 Redux)。請注意,此功能僅僅用於解決 Props drilling 的問題,而且不能替代 Redux 或 Mobx 等。固然若是你只使用狀態管理庫,則能夠隨意替把它替換掉。
這是咱們的React教程的第一部分。在後續的文章中,咱們會設計更多高級主題,包括樣式和類型檢查,以及生產部署和性能優化。