Reactjs 踏坑指南1: 一些概念

艾倫先生發表於2017-12-14

Reactjs 踏坑指南1: 知識點

  • 什麼是React
  • 虛擬DOM
  • JSX
  • 元件
  • 生命週期和狀態
  • 事件
  • 單項資料流
  • Reactjs和Angularjs的對比

React簡介

React是一個Facebook開發的UI庫。使用這個庫可以很方便的開發互動式的、具有表達力的和可重用的UI元件。本身並不是一個框架,可視為是檢視層,並且是一個以元件為基礎的高效檢視。對於React應用而言,你需要分割你的頁面,使其成為一個個的元件。也就是說你的應用是由一個個元件構成的。這種分割、複用元件的方式開發頁面,我們稱之為元件驅動開發

這個庫還使用了一種叫做虛擬DOM(Virtual DOM)的概念,這些DOM可以根據狀態有選擇的渲染。這樣,頁面就會盡量的減少DOM操作而達到保持頁面狀態的效果。

虛擬DOM

用於優化檢視的渲染和重新整理。以前我們更新檢視時,需要先清空DOM容器中的內容,然後將最新的DOM和資料追加到容器中,現在React將這一操作放到了記憶體中。

詳細說明一下:

虛擬 DOM 是在 DOM 的基礎上建立了一個抽象層,我們對資料和狀態所做的任何改動,都會被自動且高效的同步到虛擬 DOM,最後再批量同步到 DOM 中。

React 會在記憶體中維護一個虛擬 DOM 樹,當我們對這個樹進行讀或寫的時候,實際上是對虛擬 DOM 進行的。當資料變化時,然後 React 會自動更新虛擬 DOM,然後拿新的虛擬 DOM 和舊的虛擬 DOM 進行對比,找到有變更的部分,得出一個Patch,然後將這個 Patch 放到一個佇列裡,最終批量更新這些 Patch 到 DOM 中。

這樣的機制可以保證即便是根節點資料的變化,最終表現在 DOM 上的修改也只是受這個資料影響的部分,可以保證非常高效的渲染。

虛擬DOM

因為React使用了虛擬DOM,因此藉助這種方式使得在服務端渲染輸出HTML成為可能。

JSX

JSX在ECMAScript的基礎上提供了類似於XML的擴充套件。

元件

使用ReactDOM的render方法的時候,第一個引數是需要渲染的我們建立的元件,第二個是HTML的DOM節點,元件渲染之後在這裡新增。我們可以使用createClass方法建立元件。

var MyComponent = React.createClass({
    render: function(){
        return (
            <h1>Hello, world!</h1>
        );
    }
});
複製程式碼

注意:

  • 類名一定要首字母大寫
  • 新增元件屬性時,如果要使用class屬性和for屬性,屬性名不能直接用class和for,因為他們兩個是javascript的關鍵字,用className和htmlFor代替

元件建立好之後就可以在文件裡渲染出來了:

ReactDOM.render(
    <MyComponent />,
    document.getElementById('mount-point')
);
複製程式碼

建立元件的時候,可以給元件新增一些屬性,這些屬性都存在於props中。這些屬性可以通過this.props在元件內訪問,也可以在render方法渲染時使用。

var MyComponent = React.createClass({
    render: function(){
        return (
            <h1>Hello, {this.props.name}!</h1>
        );
    }
});

ReactDOM.render(
    <MyComponent name="handsome" />,
    document.getElementById('mount-point')
);
複製程式碼

生命週期和狀態

生命週期

  • componentWillMount 在渲染之前呼叫一次。
  • componentDidMount 在渲染之後呼叫一次。
  • shouldComponentUpdate 返回值決定元件是否需要update。
  • componentWillUnmount 在解除安裝元件之前呼叫。

狀態

  • getInitialState 返回State的初始值。
  • getDefaultProps 獲取props的初始值。
  • mixins 一組物件,主要用來擴充套件當前元件的功能。

每一個元件都包含一個state物件和一個props物件。State(狀態)用setState方法設定。呼叫setState方法會觸發UI的更新,也是實現互動式開發的必要基礎。如果我們要在一開始設定初始狀態(initial state),可以呼叫getInitialState方法。

state用來在建立元件的時候設定屬性,props用於渲染的時候生成想元件繫結屬性?

var MyComponent = React.createClass({
    getInitialState:function(){
        return {
            count: 5
        };
    },
    render: function(){
        return (
            <h1>Hello, {this.state.count}!</h1>
        );
    }
});
複製程式碼

事件

作為屬性包含在元件中

var Counter = React.createClass({
    incrementCount: function(){
        this.setState({
            count: this.state.count + 1
        });
    },
    getInitialState: function(){
        return {
            count: 0
        }
    },
    render: function(){
        return (
            <div class="my-component">
                <h1>Count: {this.state.count}</h1>
                <button type="button" onClick={this.incrementCount}>Increment</button>
            </div>
        );
    }
});

ReactDOM.render(
    <Counter />,
    document.getElementById('mount-point')
);
複製程式碼

單向資料流

在jquery時代,我們都是基於事件驅動,對於簡單的互動需求而言,這確實足夠了,而且開發起來非常迅速。但業務一旦複雜,這種基於事件驅動的東西就會變得很亂,頁面需要更新的DOM很多,就容易出錯。

單向資料流的概念就出現了。更新 DOM 的資料總是從頂層流下來,使用者事件不直接操作 DOM,而是操作頂層資料。這些資料從頂層流下來同時更新了DOM。你的程式碼就很少會直接處理DOM,而是隻處理資料的變更。這樣會很大程度上簡化程式碼和邏輯。

舉個例子:我點選一個button,然後頁面上一個span裡數字+1,原有的思考邏輯是“點選發生,然後資料變化,然後UI跟著變化+1”。而現在的思考邏輯是我的資料變化了,那麼我的UI會自動更新,那麼我只用考慮“點選發生,資料變化”。甚至可以把UI和資料變化分層然後處理。

具體地說:

在一個多元件結構裡,一個父元件需要負責管理狀態,並把資料通過props向下發放。

元件的狀態通過setState方法更新。資料通過設定子元件的屬性來傳遞給子元件,子元件通過this.props來獲取這些資料

例子1: 實現一個動態查詢框

var FilteredList = React.createClass({
    filterList: function(event){
        var updatedList = this.state.initialItems;
        updatedList = updatedList.filter(function(item){
            return item.toLowerCase().search(
            event.target.value.toLowerCase()) !== -1;
        });
        this.setState({items: updatedList});
    },
    getInitialState: function(){
        return {
            initialItems: [
                "Apples",
                "Broccoli",
                "Chicken",
                "Duck",
                "Eggs",
                "Fish",
                "Granola",
                "Hash Browns"
            ],
            items: []
        }
    },
    componentWillMount: function(){
        this.setState({items: this.state.initialItems})
    },
    render: function(){
        return (
            <div className="filter-list">
                <input type="text" placeholder="Search" onChange={this.filterList}/>
                <List items={this.state.items}/>
            </div>
        );
    }
});

var List = React.createClass({
    render: function(){
        return (
            <ul>
                {
                    this.props.items.map(function(item) {
                    return <li key={item}>{item}</li>
                })
            }
        </ul>
        )  
    }
});

ReactDOM.render(<FilteredList/>, document.getElementById('mount-point'));
複製程式碼

React和Angular的對比

Angular是框架,React是類庫。ng是一個完整的框架,提供了比 React 多得多的建議和功能,你只需要直接使用就可以了。而要用React,開發者通常還需要藉助別的類庫來打造一個真正的應用。比如你可能需要react-router庫來處理路由、redux或flux管理state、額外的庫做測試以及管理依賴等等。 "如果僅從框架這一點來看,選擇Angular還是React就像選擇直接購買成品電腦還是買零件自己組裝一樣。"

在大小方面,由於ng是一個大而全的框架,自帶了更多的功能。而React只載入你需要的部件,react要比ng小得多。很多應用其實用不到這種大型框架提供的所有功能。在這個越來越擁抱微服務、微應用、單一職責模組(single-responsibility packages)的時代,React 通過讓你自己挑選必要模組,讓你的應用大小真正做到量身定做。

React以JavaScript為中心,把"HTML"放到JS裡,JavaScript遠比HTML要強大。因此,增強JavaScript讓其支援標籤要比增強HTML讓其支援邏輯要合理得多。無論如何,HTML與JavaScript 都需要某種方式以粘合在一起。 Angular是以HTML而非JavaScrip為中心的,把“JS”放到HTML裡。你必須學習學一大堆Angular特有的語法(標籤),即ng框架特有的HTML補丁(shim),比如為HTML加入了迴圈語義的HTML特性。而React只需要你懂JS。

相關文章