談談 React.js 的核心入門知識

近來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

  1. 數據是何時改變的
  2. 哪個(些)DOM元素須要被更新

對於(1)而言,React提供了一個觀察者模型用於替代傳統的髒檢查(dirty checking), 也就是持續的檢查模型的變化。這也就是解釋了爲何React不須要計算哪些發生 了改變的緣由,由於它會當即知道。這個過程減小了計算量,並它應用程序變得 更平滑。但這裏真正有趣的是,React是如何管理DOM操縱的。github

對於DOM改變(2)而言,React在內存中構建了DOM的樹形表示,而且計算出哪一個 DOM元素應該被改變。對瀏覽器而言,DOM操縱是比較耗費性能的,所以咱們更傾向於 讓其變得最小化。幸運的是,React視圖儘量少的觸及到DOM元素。給予對象表示而言, 更少的DOM操縱意味着計算會更快,所以DOM改變也被儘量的減小。web

React在底層實現了一個diffing算法,該算法使用DOM的樹形表示法,當某個 節點發生變化(標記爲dirty)時它會從新計算整個子樹,你會注意到你的模型發生 了改變,由於整個子樹在以後會被從新渲染。關於該算法的詳細分析能夠參考這篇 文章

virtual dom

如何在服務端渲染

由於React在DOM表示時使用了一個虛擬(假的)DOM,所以藉助於這種方式使得在服務端 渲染輸出HTML稱爲可能(不借助於JSDom, PhantomJS等)。React還能智能的識別出 服務端渲染出來的頁面標記,並在客戶端只爲這些標記添加事件處理器,這對構建 同構web app很是有用。

有意思的是,React渲染出來的HTML標記都包含了data-reactid屬性,這有助於 React中追蹤DOM節點。

一些閱讀資料

  1. React’s diff algorithm
  2. The Secrets of React’s virtual DOM
  3. Why is React’s concept of virtual DOM said to be more performant than dirty model checking?
  4. virtual-dom

組件驅動開發

對於component-driven development而言,你在一個模板中是看不到整個網站的。 雖然在一開始你可能會遇到一些困難,可是若是進一步的使用這種思路,你會發現 它易於理解,易於維護,而且容易測試。

如何使用React的方式來思考組件開發

下面咱們來看如何實現組件驅動開發這一理念。咱們看一個例子,這個例子來源於 thinking in react 這篇文章。對於構建一個可過濾的產品列表而言,一般其包括以下的組件結構:

  • FilterableProductTable
    • SearchBar
    • ProductTable
      • ProductCategoryRow
      • ProductRow

thinking is react demo

一個組件應該包含什麼

首先,理想的,咱們應該遵照單一責任原則 來設計你的組件。當你發下你的組件應該作的更多的時候,你能夠考慮將其分割爲 更小的組件集合。

由於咱們在討論組件層級,所以在你的組件中也會使用到其餘組件。咱們首先看下 在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。

一些參考資料:

  1. JSX in depth
  2. Online JSX compiler
  3. Babel: How to use the react transformer

組件還應該包括什麼

每一個組件都應該包括一些內部狀態,處理邏輯,和事件處理器(例如按鈕點擊、輸入改變), 固然也包括一些內部的樣式。

你會遇到{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

一些參考資料:

  1. Babel: Learn ES6
  2. React ES6 announcement

組件生命週期

每一個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用於打包咱們的代碼,而且包含進咱們須要的包,而後輸出爲瀏覽器可運行的 文件。由於咱們使用JSXES6,所以咱們須要相應的工具來將其轉換爲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

  1. https://blog.risingstack.com/the-react-way-getting-started-tutorial/
  2. https://github.com/RisingStack/react-way-getting-started
  3. http://facebook.github.io/react/docs/component-specs.html
相關文章
相關標籤/搜索