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

jopen 9年前發布 | 60K 次閱讀 React.js JavaScript開發

來自:http://wwsun.me/posts/react-getting-started.html


近來React.js變得越來越流行,本文就來談一談React.js的入門實踐,通過分析一些常用的概念,以及提供一些入門 的最佳編程編程方式,僅供參考。

首先需要搞懂的是,React并不是一個框架,React提供了一些新穎的概念、庫 和編程原則讓你能夠同時在服務端和客戶端編寫快速、緊湊、漂亮的代碼來構建 你的web應用。

如果你使用React,那么可能會涉及到一些常用的概念或技術,包括:

  • ES6 React
  • 虛擬DOM(virtual DOM)
  • 組件驅動開發(component-driven development)
  • 不變性(immutability)
  • 自上而下的渲染(top-down rendering)
  • 渲染路徑和優化
  • 打包工具, ES6, 構建請求, debugging, 路由等
  • 同構React(isomorphic React)
  • </ul>

    什么是React.js

    React.js不是一個框架

    在整個Web應用的MVC架構中,你可以將React看作為視圖層,并且是一個高效 的視圖。React提供了和以往不一樣的方式來看待視圖,它以組件開發為基礎。 對React應用而言,你需要分割你的頁面,使其成為一個個的組件。也就是說,你的 應用是由這些組件組合而成的。

    你可以通過分割組件的方式去開發復雜的頁面或某個功能區塊,并且組件是可以 被復用的。這個過程大概類似于用樂高積木去瓶裝不同的物體。我們稱這種編程方式稱為 組件驅動開發

    React的一大特點是其所擁有的虛擬DOM,它讓頁面渲染變得非常的高效,并且比直接 操縱DOM變得更為可控。這兩大特點的組合使得React具有強大的自上而下的頁面渲染 能力。

    好了,React的有兩個特點:組件化和高效的虛擬DOM,但是為什么它這么被看好呢? 因為React更多的是一種概念層面的東西,而庫是其次的。也有很多其他遵從了這些思想的第三方實現。和每一個編程概念一樣,React尤其 獨有的解決方案、工具和工具。但這里并不會深入的去討論他們,而是關注React本身。

    Virtual DOM

    為了跟蹤模型層的變化,并且將其應用到DOM中(也就是渲染),我們需要注意兩個 重要的事情:

    1. 數據是什么時候改變的
    2. 哪一個(些)DOM元素需要被更新

    對于(1)而言,React提供了一個觀察者模型用于替代傳統的臟檢查(dirty checking), 也就是持續的檢查模型的變化。這也就是解釋了為什么React不需要計算哪些發生 了改變的原因,因為它會立即知道。這個過程減少了計算量,并它應用程序變得 更平滑。但這里真正有趣的是,React是如何管理DOM操縱的

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

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

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

    如何在服務端渲染

    因為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

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

    一個組件應該包含什么

    首先,理想的,我們應該遵守單一責任原則 來設計你的組件。當你發下你的組件應該做的更多的時候,你可以考慮將其分割為 更小的組件集合。

    因為我們在討論組件層級,因此在你的組件中也會使用到其他組件。我們首先看下 在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來提供模塊。下面我們需要做的 事:選擇一個合適的庫來打包我們的代碼,并且能夠讓其運行在瀏覽器上。

    因此我們需要一個打包器。目前最流行的解決方案包括兩個,分別是BrowserifyWebpack。我們選擇使用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也是由非死book提供的測試框架,并且有很多強大的特性,但這里并會詳細的 介紹它們。

    關于Jest,我推薦你閱讀和嘗試來自非死book的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://非死book.github.io/react/docs/component-specs.html
 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!