Entry to React

原教程內(nèi)容詳見精益 React 學(xué)習(xí)指南,這只是我在學(xué)習(xí)過程中的一些閱讀筆記硫麻,個人覺得該教程講解深入淺出,比目前大多數(shù)教程專業(yè)樊卓、系統(tǒng)拿愧。

1.1 Introduction to React

1.1.1 What is React?

React IS A JAVASCRIPT LIBRARY FOR BUILDING USER INTERFACES , INCLUDING

  1. React.js
  2. ReactRenders: ReactDOM / ReactServer / ReactCanvas
  3. Flux模式及其實現(xiàn)
  4. React Components
  5. React Native
  6. GraphQI + Relay

1.1.2 Basic concept in React

  1. React.js
    React.js 是 React 的核心庫,在應(yīng)用中必須先加載核心庫
    <script src="http://facebook.github.io/react/js/react.js"</script>
    <script src="http://facebook.github.io/react/js/react-dom.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
  1. ReactDOM.js
    DOM渲染器碌尔,為了在 web 頁面中顯示開發(fā)的組件浇辜,需要調(diào)用 ReactDOM.render 方法, 第一個參數(shù)是 React 組件唾戚,第二個參數(shù)為 HTMLElement柳洋。
  2. JSX
    JSX 是 React 自定義的語法,最終 JSX 會轉(zhuǎn)化為 JS 運行于頁面當(dāng)中
  3. Components
    Component是 React 中的核心概念叹坦,頁面當(dāng)中的所有元素都是通過 React 組件來表達(dá)熊镣。
  4. Virtual DOM
    React 抽象出來的虛擬 DOM 樹,虛擬樹是 React 高性能的關(guān)鍵募书。
  5. one-way reactive data flow
    React 應(yīng)用的核心設(shè)計模式绪囱,數(shù)據(jù)流向自頂向下

1.1.3 Features of React

  1. Component的組合模式
    組合模式有時候又叫做部分-整體模式,它使我們樹型結(jié)構(gòu)的問題中莹捡,模糊了簡單元素和復(fù)雜元素的概念鬼吵,客戶程序可以向處理簡單元素一樣來處理復(fù)雜元素,從而使得客戶程序與復(fù)雜元素的內(nèi)部結(jié)構(gòu)解耦。
    React 就是基于組合模式篮赢, 無論是應(yīng)用等級還是一個表單亦或是一個按鈕都視為一個組件齿椅, 然后基于組件的組合構(gòu)建整個應(yīng)用琉挖,這樣的結(jié)構(gòu)一直是前端界想要卻遲遲不來的 web component。
    基于組合模式的優(yōu)點:
  • 構(gòu)建可重用的組件:組件的開發(fā)能夠形成公司的組件庫涣脚,每個業(yè)務(wù)的開發(fā)都能積累可重用的組件示辈。
  • 無學(xué)習(xí)障礙:天然符合 HTML 的結(jié)構(gòu), 對前端開發(fā)者來說幾乎沒有學(xué)習(xí)障礙涩澡。
  • 具有彈性的架構(gòu):組合模式很簡單卻很有效顽耳,能夠構(gòu)建簡單的頁面也能構(gòu)建大型的前端應(yīng)用。
  • 源碼高可維護(hù)性:開發(fā)只是工作中的一部分妙同,應(yīng)用的上線才是噩夢的開始射富,很多大型應(yīng)用因為復(fù)制的業(yè)務(wù)邏輯導(dǎo)致無法快速響應(yīng)業(yè)務(wù)需求,可維護(hù)性低粥帚。
  1. One way data flow
    Javascript 是腳本語言胰耗,不能像靜態(tài)語言一樣通過編譯定位為題,想要清晰的定位到應(yīng)用中的 bug 需要深入了解業(yè)務(wù)代碼芒涡,對于大型前端應(yīng)用來說柴灯,因為業(yè)務(wù)代碼量很大且復(fù)雜,很難定位到 bug费尽。 然而 React 的單向數(shù)據(jù)流的設(shè)計讓前端 bug 定位變得簡單赠群, 頁面的 UI 和數(shù)據(jù)的對應(yīng)是唯一的,我們可以通過定位數(shù)據(jù)變化就可以定位頁面展現(xiàn)問題。
  2. High efficiency
    基于VirtualDOM算法可以讓只有需要改變的元素才去重渲染
  3. Separate frame design
    React.js 現(xiàn)在的版本已經(jīng)將源碼分開為 ReactDOM 和 React.js . 這就意味著 React 不僅僅能夠在 web 端工作旱幼, 甚至可以在服務(wù)端(nodejs)查描,Native 端運行。
    與此同時柏卤, 我們可以自定義自己的渲染器冬三, 實現(xiàn)比如 Three.js, Pixi.js缘缚, D3.js 的 React 方式渲染勾笆。

1.1.4 Where can React apply?

  1. web 端
  2. 原生應(yīng)用
    IOS、Android桥滨、Native 應(yīng)用
    這要歸功于 facebook 開源的 React Native窝爪。 基于 React Native , 我們將可以使用 jsx 來實現(xiàn)具有原生應(yīng)用性能的 UI 運行于 IOS 和 android 中齐媒,同時我們也可以通過 NW.js 或者 Electron 來實現(xiàn)基于 React 的桌面應(yīng)用酸舍。
  3. 服務(wù)器端渲染
    React 除了在 Web 和 Native 環(huán)境以外, 也可以通過 React 實現(xiàn)在服務(wù)器端渲染出 HTML里初。

1.2 JSX Grammar

1.2.1 Prepare running environment

  1. Babel REPL
    Babel REPL
    直接在 REPL 中寫 JSX 語法啃勉,可以實時的查看編譯后的結(jié)果。
  2. JSFiddle
    在線模式 React Fiddle
  3. Local development

1.2.2 JSX Grammar

創(chuàng)建 JSX 語法的本質(zhì)目的是為了使用基于 xml 的方式表達(dá)組件的嵌套双妨,保持和 HTML 一致的結(jié)構(gòu)淮阐,語法上除了在描述組件上比較特別以外叮阅,其它和普通的 Javascript 沒有區(qū)別。 并且最終所有的 JSX 都會編譯為原生 Javascript泣特。

  1. jsx componments
    JSX 組件分為 HTML 組件和 React 組件
    HTML 組件就是 HTML 中的原生標(biāo)簽浩姥, 如:
function render() {
       return  <p> hello, React World </p>
}
function render() {
       return <ul> 
                 <li>list item 1</li>
                 <li>list item 2</li>
              </ul>
}

React 組件就是自定義的組件,如

// 定義一個自定義組件
var CustomComponnet = React.createClass({
        render: function() {
            return <div> custom component </div>
  }
});
// 使用自定義組件
function render() {
        return <p> <CustomComponent/> </p>
}
  1. properties of jsx components
    和 html 一樣状您,JSX 中組件也有屬性勒叠,傳遞屬性的方式也相同
    對于 HTML 組件
 function render() {
      return  <p title="title" >hello, React, world </p>
 }

如果是 React 組件可以定義自定義屬性,傳遞自定義屬性的方式:

  function render() {
      return <p> <CustomComponent customProps="data"/> </p>
      }
}

屬性即可以是字符串膏孟,也可以是任意的 Javascript 變量, 傳遞方式是將變量用花括號眯分, eg:

  function render() {
      var data = {a: 1, b:2};
      return <p> <CustomComponent customProps={data}/> </p>
  }

需要注意的地方上,屬性的寫法上和 HTML 存在區(qū)別柒桑,在寫 JSX 的時候弊决,所有的屬性都是駝峰式的寫法,主要是出于標(biāo)準(zhǔn)的原因魁淳,駝峰式是 Javascript 的標(biāo)準(zhǔn)寫法飘诗,并且 React 底層是將屬性直接對應(yīng)到原生 DOM 的屬性,而原生 DOM 的屬性是駝峰式的寫法界逛,這里也可以理解為什么類名不是 class 而是 className 了, 又因為 class 和 for 還是 js 關(guān)鍵字昆稿,所以 jsx 中:

class => className
for => htmlFor

除此之外比較特殊的地方是 data-*aria-*兩類屬性是和 HTML 一致的。

  1. curly braces
  • 顯示文本
  function render() {
        var text = "Hello, World"
        return <p> {text} </p>
  }
  • 運算
funtion render() {
      var text = text;
      var isTrue = false;
      var arr = [1, 2, 3];
      return <p>
        {text}
        {isTrue ? "true" : "false"}
        {arr.map(function(it) {
           return <span> {it} </span>
        })}
        </p>
  }
  1. 限制規(guī)則
    render 方法返回的組件必須是有且只有一個根組件息拜,錯誤情況的例子
  // 無法編譯通過貌嫡,JSX 會提示編譯錯誤
  function render() {
    return (<p> .... </p>
           <p> .... </p>)
  }
  1. 組件命名空間
    JSX 可以通過命名空間的方式使用組件, 通過命名空間的方式可以解決相同名稱不同用途組件沖突的問題。如:
  function render() {
    return <p>
           <CustomComponent1.SubElement/>
           <CustomComponent2.SubElement/>
           </p>
  }

1.2.3 Understand JSX

  1. JSX 的編譯方式
    • 在 HTML 中引入 babel 編譯器, 如上 Hello World 程序中一樣该溯。
    • 離線編譯 JSX,通過 babel 編譯 JSX别惦,細(xì)節(jié)我們將在第二章中講解狈茉。
  2. JSX 到 JS 的轉(zhuǎn)化
    Hello World 程序轉(zhuǎn)化為 JS 的代碼如下:
  var Hello = React.createClass({
       displayName: 'Hello',
       render: function() {
          return React.createElement("div", null, "Hello ", this.props.name);
     }
  });
  ReactDOM.render(
       React.createElement(Hello, {name: "World"}),
       document.getElementById('container')
  );

1.3 React Components

1.3.1 Create a component

  • 創(chuàng)建一個 React 組件的方法為,調(diào)用 React.createClass 方法掸掸,傳入的參數(shù)為一個對象氯庆,對象必須定義一個 render 方法,render 方法返回值為組件的渲染結(jié)構(gòu)扰付,也可以理解為一個組件實例(React.createElement 工廠方法的返回值)堤撵,返回值有且只能為一個組件實例,或者返回 null/false羽莺,當(dāng)返回值為 null/false 的時候实昨,React 內(nèi)部通過 <noscript/> 標(biāo)簽替換
var MyComponent = React.createClass({
        render: function() {
            return <p>....</p>;
        }
});
  • Component命名空間
    可以看出 React.createClass 生成的組件類為一個 Javascript 對象。 當(dāng)我們想設(shè)置命名空間組件時盐固,可以在組件下面添加子組件
 MyComponent.SubComponent = React.createClass({...});
 MyComponent.SubComponent.Sub = React.createClass({....});
  • 無狀態(tài)組件
    除了可以通過 React.createClass 來創(chuàng)建組件以外荒给,組件也可以通過一個普通的函數(shù)定義丈挟,函數(shù)的返回值為組件渲染的結(jié)果
function StatelessComponent(props) {
        return  <div> Hello {props.name} </div>
}

無狀態(tài)組件能夠優(yōu)化性能,因為其內(nèi)部不會維護(hù)狀態(tài)志电,React 內(nèi)部不會有一個對應(yīng)的組件實例曙咽,并且也沒有生命周期 hook

1.3.2 將組件渲染到 DOM 中

當(dāng)創(chuàng)建好了組件過后,為了將組件渲染到 DOM 中顯示出來挑辆,需要兩個步驟:

  1. 在 HTML 中定義一個元素例朱,設(shè)置 id 屬性
  2. JSX 中調(diào)用 ReactDOM.render 方法, 第一個參數(shù)為 組件鱼蝉,第二個為剛才定義的 DOM 元素
<!-- 定義的 DOM 元素 -->
<div id="example"></div>
<script type="text/babel">
    // 自定義組件 
    var MyComponent = React.createClass({
        render: function() {
            return <p>....</p>;
        }
    });
    // 調(diào)用 render 方法
    ReactDOM.render(
    <MyComponent/>,
    document.getElementById('example')
    );
</script>

1.3.3 States of components

React 的渲染結(jié)果是由組件屬性和狀態(tài)共同決定的织咧,狀態(tài)和屬性的區(qū)別是伐割,狀態(tài)維護(hù)在組件內(nèi)部,屬性是由外部控制,我們先介紹組件狀態(tài)相關(guān)細(xì)節(jié):
控制狀態(tài)的 API 為:

  • this.state:組件的當(dāng)前狀態(tài)
  • getInitialState:獲取組件的初始狀態(tài)看靠,在組件加載的時候會被調(diào)用一次,返回值賦予 this.state 作為初始值
  • this.setState:組件狀態(tài)改變時稍味,可以通過 this.setState 修改狀
    • setState 方法支持按需修改隧熙,如 state 有兩個字段,僅當(dāng) setState 傳入的對象包含字段 key 才會修改屬性
  • 每次調(diào)用 setState 會導(dǎo)致重渲染調(diào)用 render 方法
  • 直接修改 state 不會重渲染組件
 var Switch = React.createClass({
        // 定義組件的初始狀態(tài)睬魂,初始為關(guān)
        getInitialState: function() {
            return {
                open: false
            }
        },
        // 通過 this.state 獲取當(dāng)前狀態(tài)
        render: function() {
            console.log('render switch component');
            var open = this.state.open;
            return <label className="switch"> 
                        <input type="checkbox" checked={open}/> 
                    </label>
        },
        // 通過 setState 修改組件狀態(tài)
        // setState 過后會 React 會調(diào)用 render 方法重渲染
        toggleSwitch: function() {
            var open = this.state.open;
            this.setState({
                open: !open
            });
        }
    })

1.3.4 Properties of components

前面已經(jīng)提到過 React 組件可以傳遞屬性給組件终吼,傳遞方法和 HTML 中無異, 可以通過 this.props 獲取組件屬性
屬性相關(guān)的 API 為:

  • this.props: 獲取屬性值
  • getDefaultProps: 獲取默認(rèn)屬性對象,會被調(diào)用一次氯哮,當(dāng)組件類創(chuàng)建的時候就會被調(diào)用际跪,返回值會被緩存起來,當(dāng)組件被實例化過后如果傳入的屬性沒有值喉钢,會返回默認(rèn)屬性值
  • this.props.children:子節(jié)點屬性
  • propTypes: 屬性類型檢查
// props.name 表示代辦事項的名稱
    var TodoItem = React.createClass({
        render: function() {
            var props = this.props;
            return <div className="todo-item">
                        <span className="todo-item__name">{props.name}</span>
                    </div>
        }
    });
    ReactDOM.render(
        <TodoItem name="代辦事項1"/>, 
         document.getElementById('example'));
  1. children屬性
    組件屬性中會有一個特殊屬性 children 姆打,表示子組件, 還是以上面一個組件為例子肠虽,我們可以換一種方式定義 name:
var TodoItem = React.createClass({
        render: function() {
            var props = this.props;
            return <div className="todo-item">
                        <span class="todo-item__name">{props.children}</span>
                    </div>
        }
    });
    ReactDOM.render(
        <TodoItem>代辦事項1</TodoItem>, 
         document.getElementById('example')); 
  1. 屬性類型檢查
    為了保證組件傳遞屬性的正確性幔戏, 我們可以通過定義 propsType 對象來實現(xiàn)對組件屬性的嚴(yán)格校驗
var MyComponent = React.createClass({
        propTypes: {
            optionalArray: React.PropTypes.array,
            optionalBool: React.PropTypes.bool,
            optionalFunc: React.PropTypes.func,
            optionalNumber: React.PropTypes.number,
            optionalObject: React.PropTypes.object,
            optionalString: React.PropTypes.string,
            // 任何可以被渲染的包括,數(shù)字税课,字符串闲延,組件,或者數(shù)組
            optionalNode: React.PropTypes.node,
            // React 元素
            optionalElement: React.PropTypes.element,
            // 枚舉
            optionalEnum: React.PropTypes.oneOf(['News', 'Photos']),
            // 任意一種類型
            optionalUnion: React.PropTypes.oneOfType([
              React.PropTypes.string,
              React.PropTypes.number,
              React.PropTypes.instanceOf(Message)
            ]),
            // 具體類型的數(shù)組
            optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number),
            // 具體類型的對象
            optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number),
            // 符合定義的對象
            optionalObjectWithShape: React.PropTypes.shape({
              color: React.PropTypes.string,
              fontSize: React.PropTypes.number
            }),
            requiredFunc: React.PropTypes.func.isRequired,
            requiredAny: React.PropTypes.any.isRequired,
            // 自定義校驗
            customProp: function(props, propName, componentName) {}
        }
    });
  1. 屬性傳遞的單向性
    我們已經(jīng)提到過 React 的單向數(shù)據(jù)流模式韩玩,數(shù)據(jù)的流動管道就是 props垒玲,流動的方向就是組件的層級自定向下的方向。所以一個組件是不能修改自身的屬性的找颓,組件的屬性一定是通過父組件傳遞而來(或者默認(rèn)屬性)合愈。
  2. 無狀態(tài)組件屬性
    對于無狀態(tài)組件,可以添加 .propTypes 和 .defaultProps 屬性到函數(shù)上。

1.3.5 組件的嵌套組合

在JSX 實例子中想暗,當(dāng)我們循環(huán)輸出 todo 列表的時候妇汗,React 會提示對于循環(huán)輸出的組件,需要有一個唯一的 key 屬性说莫。這個問題的原因在于 React 的調(diào)和機制(Reconciliation)上杨箭。

  1. 什么叫調(diào)和?
    在每次數(shù)據(jù)更新過后储狭,React 會重新調(diào)用 render 渲染出新的組件結(jié)構(gòu)互婿,新的結(jié)構(gòu)應(yīng)用到 DOM 中的過程就叫做調(diào)和過程。
  2. 為什么需要調(diào)和辽狈?
    假設(shè)我們有一個輸入組件慈参,這個時候我們正聚焦在輸入框中,當(dāng)修改值過后觸發(fā)事件導(dǎo)致了數(shù)據(jù)改變刮萌,數(shù)據(jù)改變導(dǎo)致了重渲染驮配, 這個時候輸入框被替換成了新的 DOM。 這個過程對用戶來說應(yīng)該是無感知的着茸,所以那原來的聚焦?fàn)顟B(tài)應(yīng)該被保存壮锻, 那怎么做到的呢? DOM 都被替換了涮阔,輸入狀態(tài)猜绣,選擇狀態(tài)為什么還能保存。 我們先不急著知道 How敬特,目前只需要知道這就是調(diào)和過程掰邢。
    除了保存狀態(tài)以外,調(diào)和過程還做了很多 DOM 優(yōu)化伟阔。 比如輸出一個數(shù)組的時候辣之,數(shù)據(jù)新增加或者減少了一下,或者數(shù)組項值改變了皱炉,實際上我們沒有必要刪除原來的 DOM 結(jié)構(gòu)怀估,只需要修改 DOM 的值或者刪除 DOM 就能實現(xiàn)重渲染。
    這就是為什么要有 key 屬性娃承,key 屬性能夠幫助定位 DOM 與數(shù)組元素的關(guān)系,在重渲染的時候能夠?qū)崿F(xiàn)渲染優(yōu)化怕篷。

1.4 Life circle of React Components

14.1 Components

React 中組件有自己的生命周期方法历筝,簡單理解可以為組件從出生(實例化) -> 激活 -> 銷毀生命周期 hook。通過這些 hook 方法可以自定義組件的特性廊谓。 除此之外梳猪,還可以設(shè)置一些額外的規(guī)格配置。

組件生命周期.png
這些生命周期方法都可以在調(diào)用 React.createClass 的參數(shù)對象中傳入, 之前使用過了一些方法:
render getInitialState getDefaultProps propTypes

1.4.2 mixins

Type: array mixins
mixins 可以理解為 React 的插件列表春弥,通過這種模式在不同組件之間共享方法數(shù)據(jù)或者行為只需共享 mixin 就行呛哟,mixins 內(nèi)定義的生命周期方法在組件的生命周期內(nèi)都會被調(diào)用。

var MyMixin1 = {
    componentDidMount: function() {
        console.log('auto do something when component did mount');
    }
};

var MyMixin2 = {
    someMethod: function() {
        console.log('doSomething');
    }
};

var MyComponnet = React.createClass({
    mixins: [MyMixin1, MyMixin2],
    componentDidMount: function() {
        // 調(diào)用 mixin1 共享的方法
        this.someMethod();
    }
});

1.4.3 statics

Type:object statics
statics可以定義組件的類方法
React 的組件是 面向?qū)ο驩OP 的思維匿沛,MyComponent 是一個 class扫责,class 分為類方法和實例方法,實例方法可以訪問 this, 然而類方法不能逃呼,所以我們不能在 Class 中返回狀態(tài)或者屬性鳖孤。

var MyComponent = React.createClass({
  statics: {
    customMethod: function(foo) {
      return foo === 'bar';
    }
  }
});

MyComponent.customMethod('bar');  // true

1.4.4 displayName

Type: string displayName
為了顯示調(diào)試信息,每個組件都會有一個名稱抡笼,JSX 在轉(zhuǎn)為 JS 的時候自動的設(shè)置 displayName,當(dāng)然我們也可以自定義 displayName

// Input (JSX):
var MyComponent = React.createClass({ });

// Output (JS):
var MyComponent = React.createClass({displayName: "MyComponent", });

1.4.5 生命周期方法

組件生命周期.png

1.4.6 componentWillMount

void componentWillMount()

  • 條件:第一次渲染階段在調(diào)用 render 方法前會被調(diào)用
  • 作用:該方法在整個組件生命周期只會被調(diào)用一次苏揣,所以可以利用該方法做一些組件內(nèi)部的初始化工作

1.4.7 componentDidMount

void componentDidMount()

  • 條件:第一次渲染成功過后,組件對應(yīng)的 DOM 已經(jīng)添加到頁面后調(diào)用
  • 作用:這個階段表示組件對應(yīng)的 DOM 已經(jīng)存在推姻,我們可以在這個時候做一些依賴 DOM 的操作或者其他的一些如請求數(shù)據(jù)平匈,和第三方庫整合的操作。如果嵌套了子組件增炭,子組件會比父組件優(yōu)先渲染弟跑,所以這個時候可以獲取子組件對應(yīng)的 DOM。

1.4.8 componentWillReceiveProps(newProps)

void componentWillReceiveProps(
   object nextProps
)
  • 條件: 當(dāng)組件獲取新屬性的時候防症,第一次渲染不會調(diào)用
  • 用處: 這個時候可以根據(jù)新的屬性來修改組件狀態(tài)
    componentWillReceiveProps: function(nextProps) {
       this.setState({
           likesIncreasing: nextProps.likeCount > this.props.likeCount
      });
    }

注意: 這個時候雖說是獲取新屬性蔫敲,但并不能確定屬性一定改變了饲嗽,例如一個組件被多次渲染到 DOM 中,如下面:

    var Component = React.createClass({
        componentWillReceiveProps: function(nextProps) {
            console.log('componentWillReceiveProps', nextProps.data.bar);
        },
        rener: function() {
            return <div> {this.props.data.bar} </div>
        }
    });

    var container = document.getElementById('container');
    var mydata = {bar: 'drinks'};
    ReactDOM.render(<Component data={mydata} />, container);
    ReactDOM.render(<Component data={mydata} />, container);
    ReactDOM.render(<Component data={mydata} />, container);

結(jié)果會輸出兩次 componentWillReceiveProps,雖然屬性數(shù)據(jù)沒有改變尽狠,但是仍然會調(diào)用 componentWillReceiveProps 方法袄膏。

1.4.9 shouldComponentUpdate(nextProps, nextState)

boolean shouldComponentUpdate(
   object nextProps, object nextState
)
  • 條件: 接收到新屬性或者新狀態(tài)的時候在 render 前會被調(diào)用(除了調(diào)用 forceUpdate 和初始化渲染以外)
  • 用處: 該方法讓我們有機會決定是否重渲染組件沉馆,如果返回 false斥黑,那么不會重渲染組件锌奴,借此可以優(yōu)化應(yīng)用性能(在組件很多的情況)缨叫。

1.4.10 componentWillUpdate

void componentWillUpdate(
  object nextProps, object nextState
)
  • 條件:當(dāng)組件確定要更新销钝,在 render 之前調(diào)用
  • 用處:這個時候可以確定一定會更新組件蒸健,可以執(zhí)行更新前的操作
  • 注意:方法中不能使用 setState 似忧,setState 的操作應(yīng)該在 componentWillReceiveProps 方法中調(diào)用

1.4.11 componentDidUpdate

void componentDidUpdate(
  object prevProps, object prevState
)
  • 條件:更新被應(yīng)用到 DOM 之后
  • 用處:可以執(zhí)行組件更新過后的操作

1.4.12 生命周期與單向數(shù)據(jù)流

我們知道 React 的核心模式是單向數(shù)據(jù)流盯捌,這不僅僅是對于組件級別的模式,在組件內(nèi)部 的生命周期中也是應(yīng)該符合單向數(shù)據(jù)的模式幼衰。數(shù)據(jù)從組件的屬性流入渡嚣,再結(jié)合組件的狀態(tài)识椰,流入生命周期方法腹鹉,直到渲染結(jié)束這都應(yīng)該是一個單向的過程,其間不能隨意改變組件的狀態(tài)航瞭。
組件內(nèi)部數(shù)據(jù)流.png

1.5 React & DOM

1.5.1獲取DOM元素

DOM真正被添加到HTML中的hook為

  • componentDidMount
  • componentDidUpdate

在這兩個 hook 函數(shù)中, 我們可以獲取真正的 DOM 元素滨彻,React 提供的獲取方法兩種方式

  1. findDOMNode()
    通過 ReactDOM 提供的 findDOMNode 方法亭饵, 傳入?yún)?shù)
var MyComponent = React.createClass({
    render: function() {
        return <div> .... </div>
    },
    componentDidMount: function() {
        var $root = ReactDOM.findDOMNode(this);
        console.log($root);
    }
})

需要注意的是此方法不能應(yīng)用到無狀態(tài)組件上

  1. Refs
    上面的方法只能獲取到 root 元素辜羊,那如果我的 DOM 有很多層級,我想獲取一個子級的元素呢昔驱?React 提供了 ref 屬性來實現(xiàn)這種需求骤肛。
    每個組件實例都有一個 this.refs 屬性萌衬,會自動引用所有包含 ref 屬性組件的 DOM
var MyComponent = React.createClass({
    render: function() {
        return  <div>
                    <button ref="btn">...</button>
                    <a href="" ref="link"></a>
                </div>
    },
    componentDidMount: function() {
        var $btn = this.refs.btn;
        var $link = this.refs.link;
        console.log($btn, $link);
    }
})

1.5.2 DOM事件

  1. 綁定事件
    在 React 中綁定事件的方式很簡單,只需要在元素中添加事件名稱的屬性已經(jīng)對應(yīng)的處理函數(shù)混移,如:
var MyComponent = React.creatClass({
    render: function() {
        return  <div>
                    <button onClick={this.onClick}>Click Me</button>
                </div>
    },
    onClick: function() {
        console.log('click me');
    }
});

事件名稱和其他屬性名稱一樣,服從駝峰式命名回铛。

  1. 合成事件(SyntheticEvent)
    在 React 中茵肃, 事件的處理由其內(nèi)部自己實現(xiàn)的事件系統(tǒng)完成捞附,觸發(fā)的事件都叫做 合成事件(SyntheticEvent)鸟召,事件系統(tǒng)對瀏覽器做了兼容欧募,其提供的 API 與原生的事件無異槽片。
boolean bubbles
boolean cancelable
DOMEventTarget currentTarget
boolean defaultPrevented
number eventPhase
boolean isTrusted
DOMEvent nativeEvent
void preventDefault()
boolean isDefaultPrevented()
void stopPropagation()
boolean isPropagationStopped()
DOMEventTarget target
number timeStamp
string type

和原生事件的區(qū)別在于,事件不能異步話剩盒,如:

function onClick(event) {
     console.log(event); // => nullified object.
     console.log(event.type); // => "click"
     var eventType = event.type; // => "click"

     setTimeout(function() {
         console.log(event.type); // => null
        console.log(eventType); // => "click"
  }, 0);

     this.setState({clickEvent: event}); // Won't work. this.state.clickEvent will only contain null values.
     this.setState({eventType: event.type}); // You can still export event properties.
}

原因是在事件系統(tǒng)的內(nèi)部實現(xiàn)當(dāng)中, 一個事件對象可能會被重用(也就是事件做了池化 Pooling)跟匆。當(dāng)一個事件響應(yīng)函數(shù)執(zhí)行過后,事件的屬性被設(shè)置為 null迹冤, 如果想用保持事件的值的話泡徙,可以調(diào)用
event.persist()
這樣堪藐,屬性會被保留贮勃,并且事件也會被從池中取出。

  1. 事件捕獲和冒泡
    在 DOM2.0 事件分為捕獲階段和冒泡階段枫绅,React 中通常我們注冊的事件為冒泡事件,如果要注冊捕獲階段的事件县耽,可以在事件名稱后加 Capture 如:
onClick
onClickCapture
  1. 支持事件列表
粘貼板事件 {
      事件名稱:onCopy onCut onPaste
      屬性:DOMDataTransfer clipboardData
}
編輯事件 {
      事件名稱:onCompositionEnd onCompositionStart onCompositionUpdate
      屬性:string data
}
鍵盤事件 {
      事件名稱:onKeyDown onKeyPress onKeyUp
      屬性: {
        boolean altKey
        number charCode
        boolean ctrlKey
        boolean getModifierState(key)
        string key
        number keyCode
        string locale
        number location
        boolean metaKey
        boolean repeat
        boolean shiftKey
        number which
    }
}
// 焦點事件除了表單元素以外,可以應(yīng)用到所有元素中
焦點事件 {
      事件名稱:onFocus onBlur
      屬性:DOMEventTarget relatedTarget
}
表單事件 {
      事件名稱:onChange onInput onSubmit
}
鼠標(biāo)事件 {
      事件名稱:{
        onClick onContextMenu onDoubleClick onDrag onDragEnd onDragEnter onDragExit onDragLeave onDragOver onDragStart onDrop onMouseDown onMouseEnter onMouseLeave onMouseMove onMouseOut onMouseOver onMouseUp
    }
      屬性:{
        boolean altKey
        number button
        number buttons
        number clientX
        number clientY
        boolean ctrlKey
        boolean getModifierState(key)
        boolean metaKey
        number pageX
        number pageY
        DOMEventTarget relatedTarget
        number screenX
        number screenY
        boolean shiftKey
    }
}
選擇事件 {
      事件名稱:onSelect
}
觸摸事件 {
      事件名稱:onTouchCancel onTouchEnd onTouchMove onTouchStart
      屬性:{
        boolean altKey
        DOMTouchList changedTouches
        boolean ctrlKey
        boolean getModifierState(key)
        boolean metaKey
        boolean shiftKey
        DOMTouchList targetTouches
        DOMTouchList touches
    }
}
UI 事件 {
      事件名稱:onScroll
      屬性:{
        number detail
        DOMAbstractView view
    }
}
滾輪事件 {
      事件名稱:onWheel
      屬性:{
        number deltaMode
        number deltaX
        number deltaY
        number deltaZ
    }
}
媒體事件 {
      事件名稱:{
        onAbort onCanPlay onCanPlayThrough onDurationChange onEmptied onEncrypted onEnded onError onLoadedData onLoadedMetadata onLoadStart onPause onPlay onPlaying onProgress onRateChange onSeeked onSeeking onStalled onSuspend onTimeUpdate onVolumeChange onWaiting
    }
}
圖像事件 {
      事件名稱:onLoad onError
}
動畫事件 {
      事件名稱:onAnimationStart onAnimationEnd onAnimationIteration
      屬性:{
        string animationName
        string pseudoElement
        float elapsedTime
    }
}
漸變事件 {
      事件名稱:onTransitionEnd
      屬性: {
        string propertyName
        string pseudoElement
        float elapsedTime
    }
}

1.5.3 表單事件

在 React 中比較特殊的事件是表單事件赶舆,大多數(shù)組件都是通過屬性和狀態(tài)來決定的芜茵,但是表單組件如 input, select, option 這些組件的狀態(tài)用戶可以修改绞佩,在 React 中會特殊處理這些組件的事件征炼。

  1. onChange 事件
    和普通 HTML 中的 onChange 事件不同谆奥, 在原生組件中宰译,只有 input 元素失去焦點才會觸發(fā) onChange 事件沿侈, 在 React 中,只要元素的值被修改就會觸發(fā) onChange 事件蛛淋。
var MyComponent = React.createClass({
    getInitialState: function() {
        return {
            value: ''
        }
    },
    render: function() {
        return  <div onChange={this.onChangeBubble}>
                    <input value={this.state.value} onChange={this.onChange}/>
                </div>
    },
    onChange: function(ev) {
        console.log('change: ' + ev.target.value);
        this.setState({
            value: ev.target.value
        });
    },
    // onChange 事件支持所有組件,可以被用于監(jiān)聽冒泡事件
    onChangeBubble: function(ev) {
        console.log('bubble onChange event', + ev.target.value);
    }
})
  1. 交互屬性
    表單組件中能被用戶修改的屬性叫交互屬性叛甫,包括:
value => <input> 和 <select> 組件
checked => <input type="checkbox|radio">
selected => <opiton>
  1. textarea
    在 HTML 中,textarea 的值是像如下定義的:
<textarea name="" id="" cols="30" rows="10">
        some value
</textarea>

而在 React 中棠赛, TextArea 的使用方式同 input 組件睛约,使用 value 來設(shè)置值

var MyComponent = function() {
    render: function() {
        return <div>
                    <textarea value={...} onChange={...}/>
               </div>
    }
}
  1. select 組件
    在 React 中 select 組件支持 value 值,value 值還支持多選
  <select value="B">
      <option value="A">Apple</option>
      <option value="B">Banana</option>
      <option value="C">Cranberry</option>
  </select>
  <select multiple={true} value={['B', 'C']}>
      <option value="A">Apple</option>
      <option value="B">Banana</option>
      <option value="C">Cranberry</option>
  </select>
  1. 受控組件
    在 React 中表單組件可分為兩類,受控與非受控組件商膊,受控組件是包含了 value 值的晕拆,如:
render: function() {
      return <input type="text" value="....."/>
}

為什么叫受控組件吝镣? 因為這個時候用戶不能修改 input 的值末贾, input 的值永遠(yuǎn)是 value 固定了的值。如果去掉 value 屬性拴测,那么就可以輸入值了寸齐。
那如何修改受控組件的值呢渺鹦? 如上面的例子中塞颁, 添加 onChange 事件祠锣,事件內(nèi)修改 value 屬性,value 屬性的值會被設(shè)置到組件的 value 中澡腾。

  1. 非受控組件
    沒有 value 值的 input
render: function() {
     return <input type="text"/>
}

可以通過 defaultValue 屬性來設(shè)置默認(rèn)值

render: function() {
      return <input type="text" defaultValue="Default Value">
}

類似的對于 checkbox 有 defaultChecked 屬性
需要注意的是,默認(rèn)值只適用于第一次渲染澜公,在重渲染階段將不會適用蜕青。

  1. checkbox & radio
    checkbox 和 radio 比較特殊, 如果在 onChange 事件中調(diào)用了 preventDefault 贺喝,那么瀏覽器不會更新 checked 狀態(tài),即便事實上組件的值已經(jīng) checked 或者 unchecked 了 染苛。
var CheckBox = React.createClass({
      getInitialState: function(){
          return {
              checked: false
        }
    },
    render: function() {
        return  <div>
            <input type="checkbox" 
                checked={this.state.checked} 
                onChange={this.onChange}/>
        </div>
    },
    onChange: function(ev) {
        this.setState({
            checked: true
        });
        ev.preventDefault();
    }
})

這個例子里邊,checked 雖然更新為 true 畔师,但是 input 的值 checked 為 false
那應(yīng)如何處理 checkbox 呢?

  • 避免調(diào)用 ev.preventDefault
  • 在 setTimeout 中處理 checked 的修改
  • 使用 click 事件

1.5.4 Style屬性

在 React 中伯铣,可以直接設(shè)置 style 屬性來控制樣式,不過與 HTML 不同的是蹬蚁, 傳入的 style 值為一個object, 對象的所有 key 都是駝峰式命名叽粹,eg:

render: function() {
    var style = {
        backgroundColor: 'red',
        height: 100,
        width: 100
    }
    return <div style={style}></div>
}

其中還可以看到不同的地方時,為了簡寫寬度高度值虫几,可以直接設(shè)置數(shù)字锤灿,對應(yīng) 100 -> 100px。如果某些屬性不需要添加 px 后綴辆脸,React 也會自動去除但校。

通過屬性值駝峰式的原因是 DOM 內(nèi)部訪問 style 也是駝峰式。如果需要添加瀏覽器前綴瑞 -webkit-状囱、-ms- 大駝峰(除了 ms ), 如:

var divStyle = {
  WebkitTransition: 'all', // 'W' 是大寫
  msTransition: 'all'      // 'ms' 為小寫
};

在以前的前端開發(fā)方式是 樣式結(jié)構(gòu)和邏輯要分離, 而現(xiàn)在 React 中卻有很多人推崇** inline **的樣式倘是。 在我看來因人而異亭枷,React 的這種模式也能做到樣式模塊化,樣式重用(借用 Js 的特點)搀崭。并且因為 React 的實現(xiàn)方式叨粘,Inline 樣式的性能甚至比 class 的方式高。

1.6 Flux

1.6.1 Flux 介紹

簡單來講瘤睹,F(xiàn)lux 是 Facebook 引入到 React 中的一種前端架構(gòu)升敲,通過定義其核心單向數(shù)據(jù)流的方式,讓 React 應(yīng)用更加健壯默蚌。同時冻晤,這種應(yīng)用架構(gòu)也具有普適性苇羡,可以應(yīng)用到其他任意前端項目中绸吸,甚至可以應(yīng)用到客戶端應(yīng)用開發(fā)中,也就是說 Flux 更應(yīng)該叫做一種架構(gòu)模式(Pattern)设江。

1.6.2 MVC 架構(gòu)之痛

MVC 的實現(xiàn)可能有很多種方式锦茁,比較靈活,但基本本質(zhì)不會改變叉存,只是三者間的數(shù)據(jù)傳遞方向可能會改變码俩,即便是 MVP 模式也只是 MVC 的變種,所以為了統(tǒng)一我們且以下圖的 MVC 方式來討論歼捏。


MVC.png
  1. 概念
  • Model: 負(fù)責(zé)保存應(yīng)用數(shù)據(jù)稿存,和后端交互同步應(yīng)用數(shù)據(jù)
  • View: 負(fù)責(zé)渲染頁面 HTML DOM
  • Controller: 負(fù)責(zé)連接 View 和 Model , Model 的任何改變會應(yīng)用到 View 中瞳秽,View 的操作會通過 Controller 應(yīng)用到 Model 中
  • 關(guān)系:Model, View, Controller 都是多對多關(guān)系瓣履。
  1. 流程
    以 TODOMVC 為例子用戶添加一個 todo 的交互流程:
    View -> Action -> Controller -> Model -> View
  • View -> Action: 添加按鈕事件或者 input 輸入的提交事件
  • Action -> Controller: 控制器響應(yīng) View 事件
  • Controller -> Model: 控制器依賴 Model, 調(diào)用 Model 添加 todo
  • Model -> View: View 監(jiān)聽 Model 的改變添加 todo 事件,在 HTML 中添加一個新的 Todo 視圖
  1. 問題
    對于新增一個 todo 练俐,需要編寫一個視圖渲染處理函數(shù)袖迎,函數(shù)內(nèi)添加新項目到列表中。同理對于刪除一個 todo,也會有一個處理函數(shù)燕锥。當(dāng)業(yè)務(wù)邏輯變多過后辜贵,可能有很多模型需要做增刪改的功能,與之對應(yīng)的就是我們需要精心構(gòu)建這么多的渲染處理函數(shù)归形。 這種局部更新模式是高性能的關(guān)鍵所在托慨,但問題是:
  • 更新邏輯復(fù)雜,需要編寫大量的局部渲染函數(shù)
  • 問題定位困難连霉,頁面的當(dāng)前狀態(tài)是有數(shù)據(jù)和這些局部更新函數(shù)確定的
  1. 如何解決
    如果渲染函數(shù)只有一個榴芳,統(tǒng)一放在 App 控制器中,每次更新重渲染頁面跺撼,這樣的話:
    • 任何數(shù)據(jù)的更新都只用調(diào)用重渲染就行
    • 數(shù)據(jù)和當(dāng)前頁面的狀態(tài)是唯一確定的
      重渲染也有弊端窟感,會帶來嚴(yán)重的性能問題,重渲染和局部渲染各有好壞歉井,對 MVC 來說這是一個兩難的選擇柿祈,無法做到魚和熊掌兼得。

1.6.3 Flux 架構(gòu)

通過 React + Flux 就可以完美解決 MVC 的問題哩至。簡單來說在 Flux 架構(gòu)中直接剝離了控制器層躏嚎,MVC 架構(gòu)變成了 MV + Flux 架構(gòu)。

  • 重渲染: 在 React 中每次渲染都是重渲染菩貌,且不影響頁面性能卢佣,是因為重渲染的是 Virtual Dom。這就意味著完全不用去關(guān)系重渲染問題箭阶,增刪改的渲染都和初始化渲染相同入口
  • 數(shù)據(jù)和狀態(tài)一致性: Store 的數(shù)據(jù)確定應(yīng)用唯一的狀態(tài)
  1. 概念
  • one way data flow

    這是 Flux 架構(gòu)的核心思想虚茶,從圖中可以看到,數(shù)據(jù)的流向從action 到 view 的一個單向流仇参。
    單項數(shù)據(jù)流.png
  • Action

    Action 可以理解為對應(yīng)用數(shù)據(jù)修改的指令嘹叫,任何修改應(yīng)用數(shù)據(jù)的行為都必須需通過觸發(fā) action 來修改。Action 可以來自于 View诈乒,也可以來自服務(wù)端的數(shù)據(jù)更新罩扇。
    action.png
  • Action creator
    為了抽象 Action ,提供一些輔助的語義化的方法來創(chuàng)建 Action怕磨,這些輔助方法叫做 Action Creator喂饥。


    Action creator.png
  • Stores
    應(yīng)用的數(shù)據(jù)中心,所有應(yīng)用數(shù)據(jù)都存放在這里控制肠鲫,同時包含數(shù)據(jù)的控制行為员帮,可能包含多個 store.
  • Dispatcher
    action 的控制者,所有 action 都會通過 dispatcher滩届,由 dispatcher 控制 action 是否應(yīng)該傳入到 store 中集侯,Dispatcher 是一個單例被啼。
  • View
    頁面的視圖,對應(yīng) React 的 Component, 視圖可以觸發(fā) action 到 dispatcher棠枉。
    需要區(qū)別出一種叫控制器 View(Controller View)的類型浓体,這種 View 可以知曉 store 數(shù)據(jù),把 store 數(shù)據(jù)轉(zhuǎn)化為自身的狀態(tài)辈讶,在將數(shù)據(jù)傳遞給其他 view 命浴。 并且可以監(jiān)聽 store 數(shù)據(jù)的改變,當(dāng) store 數(shù)據(jù)改變過后重新設(shè)置狀態(tài)觸發(fā)重渲染贱除。 可以將控制器 View 對應(yīng) MVC 中的控制器生闲,但是差別很大,控制器 View 唯一多做的事情就是監(jiān)聽 store 數(shù)據(jù)改變月幌,沒有其他任何業(yè)務(wù)處理邏輯碍讯。
  1. 流程
    同樣以 TODOMVC 的添加 todo 為例,F(xiàn)lux 中的流程為:
View -> Action(Action Creator -> Action) -> Dispatcher -> Store -> Controller View -> View
  • View -> Action: 添加按鈕事件或者 input 輸入的提交事件扯躺,View 中將事件轉(zhuǎn)化為 action, action 由 Action Creator 創(chuàng)建捉兴。
  • Action -> Dispatcher: action 統(tǒng)一由 Dispatcher 分配
  • Dispatcher -> Store: Dispatcher 分配 action 到 Store
  • Store -> Controller View: 控制器 View 監(jiān)聽 store 的數(shù)據(jù)改變,將數(shù)據(jù)轉(zhuǎn)化為自身屬性
  • Controller View -> View: 數(shù)據(jù)改變自動重渲染所有視圖
    與MVC的對比
  • 渲染策略: 數(shù)據(jù)改變 Flux 自動渲染录语,MVC 手動編寫更新函數(shù)
  • 事件觸發(fā)策略: Flux 中所有 action 交給 dispather 分配倍啥,MVC 中交給對應(yīng)的控制器分配
  • Flux 在核心策略上的不同是解決 MVC 架構(gòu)問題的關(guān)鍵

1.6.4 理解 Flux 架構(gòu)

Flux 架構(gòu)是非常優(yōu)雅簡潔的,合理利用了一些優(yōu)秀的架構(gòu)思維

  1. 分而治之(Divide And Conquer)
    數(shù)據(jù)的處理過程是 Store -> Controller View -> View澎埠。 所有數(shù)據(jù)來自于 Store虽缕,頁面的渲染層級為 Store 將數(shù)據(jù)傳入 Controller View, 再由 Controller View 傳入子 View , 一直到 View 的葉子節(jié)點。
    這個是一個典型的分而治之策略蒲稳,將大的頁面拆分為小的模塊氮趋,再由小的模塊拆分為小的組件,具體組件負(fù)者組件自身的問題弟塞,所有子組件都是自私的凭峡,不用關(guān)心“大家”拙已,只用關(guān)心“小家”决记。
  2. 合而治之 - 中心化控制
    Flux 把所有的 View 都視作愚民,Store 視作資源的擁有者為統(tǒng)治者倍踪,統(tǒng)治者需要提供資源(數(shù)據(jù))給平民系宫,但是如果平民企圖對資源修改(Mutation),必須得先通知給統(tǒng)治者建车,讓統(tǒng)治者決定是否做處理扩借。
    我們?yōu)?Flux 中的概念分配角色
    View: 平民
    Action: 資源修改操作
    Dispatcher: 審核官
    Store: 統(tǒng)治者
    一個企圖修改資源的操作可以描述為:
View Require Mutation -> Action -> Dispatcher -> Store -> Mutate Handler

平民提交 Mutation 請求,由審核官控制缤至,審核通過后遞交給統(tǒng)治者潮罪,統(tǒng)治者再分配給親信做資源 Mutation
合而治之的策略也等于中心化控制策略, 作為統(tǒng)治者既要懂得放權(quán)利(資源的分配),也要懂得控制權(quán)利(資源的修改)嫉到,這種收縮自如的合理性是 Flux 簡潔的根本沃暗。
同時這種思維帶來的優(yōu)點如下:

  • View 的獨立性和簡單性:View 自身的邏輯簡單,不需要知道太多事情何恶,只關(guān)心上級傳來的數(shù)據(jù)孽锥,這種模式使得 View 是低耦合的,簡潔的细层。
  • 高可維護(hù)性:中心化控制知道所有對資源的操作惜辑,如果發(fā)生 bug, 可以很快定位問題
  1. 函數(shù)式編程思想
    在 Flux 中數(shù)據(jù)的單向流動依賴于 View 的確定性,相同的數(shù)據(jù)傳入相同的組件疫赎,得到的結(jié)果必然要相同盛撑,這是函數(shù)式編程的思想。
    為了保證組件也能做到 “純函數(shù)” 的特性捧搞,相同的屬性會得到相同的渲染結(jié)果撵彻。 在寫 React 組件的時候盡量準(zhǔn)守一下約定:
1.盡量使用無狀態(tài)組件
2.除了控制類組件以外其他組件避免使用組件狀態(tài)
3.可以通過屬性計算出來的狀態(tài)不要用狀態(tài)來表示
4.組件的渲染避免外部依賴,按照純函數(shù)的方式寫

函數(shù)式的優(yōu)點也是無副作用組件的優(yōu)點:

  • 無耦合实牡,可移植性強: 組件可重用性高
  • 可測試性高:組件無依賴陌僵,可以很容易的單獨測試組件
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市创坞,隨后出現(xiàn)的幾起案子碗短,更是在濱河造成了極大的恐慌,老刑警劉巖题涨,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件偎谁,死亡現(xiàn)場離奇詭異,居然都是意外死亡纲堵,警方通過查閱死者的電腦和手機巡雨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來席函,“玉大人铐望,你說我怎么就攤上這事∶剑” “怎么了正蛙?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長营曼。 經(jīng)常有香客問我乒验,道長,這世上最難降的妖魔是什么蒂阱? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任锻全,我火速辦了婚禮狂塘,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鳄厌。我一直安慰自己睹耐,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布部翘。 她就那樣靜靜地躺著硝训,像睡著了一般。 火紅的嫁衣襯著肌膚如雪新思。 梳的紋絲不亂的頭發(fā)上窖梁,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天,我揣著相機與錄音夹囚,去河邊找鬼纵刘。 笑死,一個胖子當(dāng)著我的面吹牛荸哟,可吹牛的內(nèi)容都是我干的假哎。 我是一名探鬼主播,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼鞍历,長吁一口氣:“原來是場噩夢啊……” “哼舵抹!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起劣砍,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤惧蛹,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后刑枝,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體香嗓,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年装畅,在試婚紗的時候發(fā)現(xiàn)自己被綠了靠娱。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡掠兄,死狀恐怖像云,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情徽千,我是刑警寧澤苫费,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布汤锨,位于F島的核電站双抽,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏闲礼。R本人自食惡果不足惜牍汹,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一铐维、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧慎菲,春花似錦嫁蛇、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至解幼,卻和暖如春抑党,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背撵摆。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工底靠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人特铝。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓暑中,卻偏偏與公主長得像,于是被迫代替她去往敵國和親鲫剿。 傳聞我的和親對象是個殘疾皇子鳄逾,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 自己最近的項目是基于react的,于是讀了一遍react的文檔灵莲,做了一些記錄(除了REFERENCE部分還沒開始讀...
    潘逸飛閱讀 3,339評論 1 10
  • GUIDS 第一章 為什么使用React严衬? React 一個提供了用戶接口的JavaScript庫。 誕生于Fac...
    jplyue閱讀 3,519評論 1 11
  • react 基本概念解析 react 的組件聲明周期 react 高階組件笆呆,context, redux 等高級...
    南航閱讀 1,052評論 0 1
  • It's a common pattern in React to wrap a component in an ...
    jplyue閱讀 3,251評論 0 2
  • 青春是個很有意思的時期赠幕,詩和遠(yuǎn)方俄精、夢想和姑娘占據(jù)了半壁江山。那是個神奇的年代榕堰,一無所有的年紀(jì)里就敢給心愛的姑娘許諾...
    碼字的黃小邪閱讀 542評論 2 4