近來React.js變得愈來愈流行,本文就來談一談React.js的入門實踐,經過分析一些經常使用的概念,以及提供一些入門 的最佳編程編程方式,僅供參考。javascript
首先須要搞懂的是,React並非一個框架,React提供了一些新穎的概念、庫 和編程原則讓你可以同時在服務端和客戶端編寫快速、緊湊、漂亮的代碼來構建 你的web應用。html
若是你使用React,那麼可能會涉及到一些經常使用的概念或技術,包括:java
- ES6 React
- 虛擬DOM(virtual DOM)
- 組件驅動開發(component-driven development)
- 不變性(immutability)
- 自上而下的渲染(top-down rendering)
- 渲染路徑和優化
- 打包工具, ES6, 構建請求, debugging, 路由等
- 同構React(isomorphic React)
什麼是React.js
React.js不是一個框架
在整個Web應用的MVC架構中,你能夠將React看做爲視圖層,而且是一個高效 的視圖。React提供了和以往不同的方式來看待視圖,它以組件開發爲基礎。 對React應用而言,你須要分割你的頁面,使其成爲一個個的組件。也就是說,你的 應用是由這些組件組合而成的。node
你能夠經過分割組件的方式去開發複雜的頁面或某個功能區塊,而且組件是能夠 被複用的。這個過程大概相似於用樂高積木去瓶裝不一樣的物體。咱們稱這種編程方式稱爲 組件驅動開發。react
React的一大特色是其所擁有的虛擬DOM,它讓頁面渲染變得很是的高效,而且比直接 操縱DOM變得更爲可控。這兩大特色的組合使得React具備強大的自上而下的頁面渲染 能力。webpack
好了,React的有兩個特色:組件化和高效的虛擬DOM,可是爲何它這麼被看好呢? 由於React更多的是一種概念層面的東西,而庫是其次的。也有不少其餘聽從了這些思想的第三方實現。和每個編程概念同樣,React尤爲 獨有的解決方案、工具和工具。但這裏並不會深刻的去討論他們,而是關注React自己。git
Virtual DOM
爲了跟蹤模型層的變化,而且將其應用到DOM中(也就是渲染),咱們須要注意兩個 重要的事情:es6
- 數據是何時改變的
- 哪個(些)DOM元素須要被更新
對於(1)而言,React提供了一個觀察者模型用於替代傳統的髒檢查(dirty checking), 也就是持續的檢查模型的變化。這也就是解釋了爲何React不須要計算哪些發生 了改變的緣由,由於它會當即知道。這個過程減小了計算量,並它應用程序變得 更平滑。但這裏真正有趣的是,React是如何管理DOM操縱的。github
對於DOM改變(2)而言,React在內存中構建了DOM的樹形表示,而且計算出哪一個 DOM元素應該被改變。對瀏覽器而言,DOM操縱是比較耗費性能的,所以咱們更傾向於 讓其變得最小化。幸運的是,React視圖儘量少的觸及到DOM元素。給予對象表示而言, 更少的DOM操縱意味着計算會更快,所以DOM改變也被儘量的減小。web
React在底層實現了一個diffing
算法,該算法使用DOM的樹形表示法,當某個 節點發生變化(標記爲dirty)時它會從新計算整個子樹,你會注意到你的模型發生 了改變,由於整個子樹在以後會被從新渲染。關於該算法的詳細分析能夠參考這篇 文章。
如何在服務端渲染
由於React在DOM表示時使用了一個虛擬(假的)DOM,所以藉助於這種方式使得在服務端 渲染輸出HTML稱爲可能(不借助於JSDom, PhantomJS等)。React還能智能的識別出 服務端渲染出來的頁面標記,並在客戶端只爲這些標記添加事件處理器,這對構建 同構web app很是有用。
有意思的是,React渲染出來的HTML標記都包含了data-reactid
屬性,這有助於 React中追蹤DOM節點。
一些閱讀資料
- React’s diff algorithm
- The Secrets of React’s virtual DOM
- Why is React’s concept of virtual DOM said to be more performant than dirty model checking?
- virtual-dom
組件驅動開發
對於component-driven development而言,你在一個模板中是看不到整個網站的。 雖然在一開始你可能會遇到一些困難,可是若是進一步的使用這種思路,你會發現 它易於理解,易於維護,而且容易測試。
如何使用React的方式來思考組件開發
下面咱們來看如何實現組件驅動開發這一理念。咱們看一個例子,這個例子來源於 thinking in react 這篇文章。對於構建一個可過濾的產品列表而言,一般其包括以下的組件結構:
- FilterableProductTable
- SearchBar
- ProductTable
- ProductCategoryRow
- ProductRow
一個組件應該包含什麼
首先,理想的,咱們應該遵照單一責任原則 來設計你的組件。當你發下你的組件應該作的更多的時候,你能夠考慮將其分割爲 更小的組件集合。
由於咱們在討論組件層級,所以在你的組件中也會使用到其餘組件。咱們首先看下 在ES5中組件代碼是什麼樣子的:
var HelloComponent = React.createClass({ render: function() { return <div>Hello {this.props.name}</div>; } });
若是使用ES6,你的組件代碼能夠這樣寫:
class HelloComponent extends React.Component { render() { return <div>Hello {this.props.name}</div>; } }
JS和JSX
正如你說看到的,咱們的組件是JS和HTML代碼的混合,你可能會以爲這很糟糕,由於 MVC一直在教咱們儘量的隔離視圖和控制邏輯。但另外一方,這種混合得到另外一個層面的 單一責任,他使得組件更加的靈活和可重用。
固然,在React中你也可使用純JS來編寫你的組件:
render () { return React.createElement("div", null, "Hello ", this.props.name); }
是的,你會發現這很麻煩,沒有使用HTML來得直觀。所以React提供了JSX (JavaScript eXtension)語法讓你可以在JS中書寫HTML代碼。
render () { return <div>Hello {this.props.name}</div>; }
什麼是JSX
JSX在ECMAScript的基礎上提供了相似於XML的擴展。 JSX和HTML有點像,但也有不同的地方。例如,HTML中的class
屬性在JSX中 爲className
。其餘不同的地方,你能夠參考FB的 HTML Tags vs. React Components這篇文章。
可是因爲瀏覽器原生並不支持JSX,所以咱們須要將其編譯爲JS,有不少方法可以 完成這個任務,後面咱們會提到這些方法。此外,Babel也可以講JSX編譯爲JS。
一些參考資料:
組件還應該包括什麼
每一個組件都應該包括一些內部狀態,處理邏輯,和事件處理器(例如按鈕點擊、輸入改變), 固然也包括一些內部的樣式。
你會遇到{this.props.name}這樣的代碼片斷,這意味着你能夠經過屬性的方式 先組件內傳遞數據,例如<MyComp name='weiwei sun' />
。這讓組件變得可重用, 而且可以自上而下的向嵌套的組件傳遞數據。
示例代碼以下:
class UserName extends React.Component { render() { return <div>name: {this.props.name}</div>; } } class User extends React.Component { render() { return <div> <h1>City: {this.props.user.city}</h1> <UserName name={this.props.user.name} /> </div>; } } var user = { name: 'John', city: 'San Francisco' }; React.render(<User user={user} />, document.body);
React擁抱ES6
在React中嘗試編寫ES6是個很是不錯的開始,React並非一開始就支持ES6的, 而是從v0.13.0
開始支持的。你會常常用到的ES6特性包括類、箭頭函數、consts 和模塊。例如,咱們會常常從繼承React.Component
類開始編寫咱們的組件。
還有一點須要注意的是,並非每一個瀏覽器都支持ES6,所以目前狀況下,咱們須要 使用一些工具將咱們編寫的ES6代碼轉換爲ES5代碼,我推薦使用 Babel。
一些參考資料:
組件生命週期
每一個React組件在加載時都有特定的生命週期,在此期間不一樣的方法會被執行。 下面簡單介紹React組件的生命週期:
componentWillMount
該方法會在組件render
以前執行,而且永遠只執行一次。
componentDidMount
該方法會在組件加載完畢以後當即執行。此時,組件已經完成了DOM結構的渲染, 並能夠經過this.getDOMNode()
方法來訪問。
componentWillReceiveProps
組件接收到一個新的prop時會被執行,且該方法在初始render
時不會被調用。
shouldComponentUpdate
在組件接收到新的props或state時被執行。
componentWillUpdate
在組件接收到新的props或者state但尚未render時被執行。 在初始化時不會被執行。
componentDidUpdate
在組件完成更新後當即執行。在初始化時不會被執行。 通常會在組件完成更新後被使用。
componentWillUnMount
在組件從DOM中unmount後當即執行。該方法主要用來執行一些必要的清理任務。
關於生命週期的具體內容,你能夠參考官方文檔。
在打包時使用Webpack和Babel
咱們會常常用到一些工具,首先一個是node.js
的模塊系統和它的包管理工具npm
。 咱們會編寫node風格的代碼來require
咱們須要的東西。而且react
自己也是一個獨立的 npm包。
一般你有兩種選擇,commonJS或者ES6:
var React = require('react/addon'); var MyComponent = React.createClass({ // do something }); module.exports = MyComponent;
或者
import React from 'react/addons'; class MyComponent extends React.Component { // do something use es6 } export default MyComponent;
例如,咱們會使用debug模塊來調試, 使用superagent模塊來編寫請求。
如今,咱們有了Node的依賴管理系統,而且使用npm
來提供模塊。下面咱們須要作的 事:選擇一個合適的庫來打包咱們的代碼,而且可以讓其運行在瀏覽器上。
所以咱們須要一個打包器。目前最流行的解決方案包括兩個,分別是Browserify和 Webpack。咱們選擇使用Webpack,由於Webpack 更適合於React社區。
Webpack是如何工做的
Webpack用於打包咱們的代碼,而且包含進咱們須要的包,而後輸出爲瀏覽器可運行的 文件。由於咱們使用JSX
和ES6
,所以咱們須要相應的工具來將其轉換爲ES5。事實上, Babel可以同時作這兩件事。使用Webpack可以很輕鬆的完成這些任務,由於Webpack 是面向配置的。
使用以下命令開始:
npm init npm install webpack --save-dev npm install babel --save-dev npm install babel-loader --save-dev
而後建立webpack.config.js
文件,咱們須要使用ES5來編寫該文件,由於它是 webpack的配置文件。一個典型的配置方式以下:
var path = require('path'); module.exports = { entry: path.resolve(__dirname, '../src/client/scripts/client.js'), output: { path: path.resolve(__dirname, '../dist'), filename: 'bundle.js' }, module: { loaders: [ { test: /src\/.+.js$/, exclude: /node_modules/, loader: 'babel' } ] } };
運行webpack
命令你能夠執行打包流程。這以後你能夠只在頁面中包含bundle.js
便可。 以下:
<script src='bundle.js'></script>
(提示:你可使用node-static
來存放你的靜態資源文件,使用npm install -g node-static
來安裝,並使用static .
來啓動)。
項目結構
一個典型的項目結構你能夠參考這個倉庫。
config/ app.js webpack.js (js config over json -> flexible) src/ app/ (the React app: runs on server and client too) components/ __tests__ (Jest test folder) AppRoot.jsx Cart.jsx Item.jsx index.js (just to export app) app.js client/ (only browser: attach app to DOM) styles/ scripts/ client.js index.html server/ index.js server.js .gitignore .jshintrc package.json README.md
如何測試React組件
對於React組件的測試,這裏推薦使用Jest, Jest也是由Facebook提供的測試框架,而且有不少強大的特性,但這裏並會詳細的 介紹它們。
關於Jest,我推薦你閱讀和嘗試來自Facebook的Tutorial。
對於ES6代碼的測試,你能夠參考 React ES6 Testing。
小結
本文簡單介紹了React的基礎原理,一些相關的編程技術。後續還會整合一些資料 談一談Flux和同構。
Statement
本文翻譯自:https://blog.risingstack.com/the-react-way-getting-started-tutorial/ 有增刪改。
References
- https://blog.risingstack.com/the-react-way-getting-started-tutorial/
- https://github.com/RisingStack/react-way-getting-started
- http://facebook.github.io/react/docs/component-specs.html