React 技術棧

分類:技術博客
本文源地址:jstraining/docs/react.md - 阮一峰
注:本文只是阮一峰老師《全棧工程師培訓材料》其中的React部分

React 技術棧


React 是目前最熱門的前端框架。

  • Facebook 公司2013年推出
  • 現在最好的社區支持和生態圈
  • 大量的第三方工具


React 的優點

  • 組件模式:代碼復用和團隊分工
  • 虛擬 DOM:性能優勢
  • 移動端支持:跨終端

React 的缺點

  • 學習曲線較陡峭
  • 全新的一套概念,與其他所有框架截然不同
  • 只有采用它的整個技術棧,才能發揮最大威力

總結:React 非常先進和強大,但是學習和實現成本都不低


JSX 語法

React 使用 JSX 語法,JavaScript 代碼中可以寫 HTML 代碼。

let myTitle = <h1>Hello, world!</h1>;

JSX 語法解釋

(1)JSX 語法的最外層,只能有一個節點。

// 錯誤
let myTitle = <p>Hello</p><p>World</p>;

(2)JSX 語法中可以插入 JavaScript 代碼,使用大括號。

let myTitle = <p>{'Hello ' + 'World'}</p>

Babel 轉碼器

JavaScript 引擎(包括瀏覽器和 Node)都不認識 JSX,需要首先使用 Babel 轉碼,然后才能運行。

<script src="react.js"></script>
<script src="react-dom.js"></script>
<script src="babel.min.js"></script></p>
<script type="text/babel">
  // ** Our code goes here! **
</script> 

React 需要加載兩個庫:React 和 React-DOM,前者是 React 的核心庫,后者是 React 的 DOM 適配庫。

Babel 用來在瀏覽器轉換 JSX 語法,如果服務器已經轉好了,瀏覽器就不需要加載這個庫。


課堂練習:JSX 語法

瀏覽器打開demos/jsx-demo/index.html,按照《操作說明》,完成練習。

ReactDOM.render(
  <span>Hello World!</span>,
  document.getElementById('example')
); 

示例:React 組件

React 允許用戶定義自己的組件,插入網頁。

瀏覽器打開demos/react-component-demo/index1.html,按照《操作說明》,仔細查看源碼。

class MyTitle extends React.Component {
  render() {
    return <h1>Hello World</h1>;
  }
};
ReactDOM.render(
  <MyTitle/>,
  document.getElementById('example')
); 

課堂練習:組件的參數

組件可以從外部傳入參數,內部使用this.props獲取參數。

打開demos/react-component-demo/index2.html,按照《操作說明》,完成練習。

class MyTitle extends React.Component {
  render() {
    return <h1
      style={{color: this.props.color}}
    >Hello World</h1>;
  }
};
<MyTitle color="red" />, 

示例:組件的狀態

組件往往會有內部狀態,使用this.state表示。

瀏覽器打開demos/react-component-demo/index3.html,按照《操作說明》,仔細查看源碼。


課堂練習:React 組件實戰

瀏覽器打開demos/react-component-demo/index4.html,按照《操作說明》,完成練習。


組件的生命周期

React 為組件的不同生命階段,提供了近十個鉤子方法。

  • componentWillMount():組件加載前調用
  • componentDidMount():組件加載后調用
  • componentWillUpdate(): 組件更新前調用
  • componentDidUpdate(): 組件更新后調用
  • componentWillUnmount():組件卸載前調用
  • componentWillReceiveProps():組件接受新的參數時調用

我們可以利用這些鉤子,自動完成一些操作。


課堂練習:組件的生命周期

組件可以通過 Ajax 請求,從服務器獲取數據。Ajax 請求一般在componentDidMount方法里面發出。

componentDidMount() {
  const url = '...';
  $.getJSON(url)
    .done()
    .fail();
}

打開demos/react-lifecycle-demo/index.html,按照《操作說明》,完成練習。


React 組件庫

React 的一大優勢,就是網上有很多已經寫好的組件庫,可以使用。

React-Bootstrap:https://react-bootstrap.github.io/


示例:ReCharts

ReCharts 是一個 React 圖表組件庫。http://recharts.org/

瀏覽器打開demos/recharts-demo/index.html,按照《操作說明》,仔細查看源碼,體會 JSX 語法對表達復雜組件的優勢。

<LineChart width={1000} height={400} data={data}>
  <XAxis dataKey="name"/>
  <YAxis/>
  <CartesianGrid stroke="#eee" strokeDasharray="5 5"/>
  <Line type="monotone" dataKey="uv" stroke="#8884d8" />
  <Line type="monotone" dataKey="pv" stroke="#82ca9d" />
</LineChart>

React 的核心思想

View 是 State 的輸出。

view = f(state)

上式中,f表示函數關系。只要 State 發生變化,View 也要隨之變化。


React 的本質是將圖形界面(GUI)函數化。

const person = {
  name: "michel",
  age: 31
}
const App = ({ person }) => <h1>{ person.name }</h1>
ReactDOM.render( <App person={person} />, document.body) 

React 沒有解決的問題

React 本身只是一個 DOM 的抽象層,使用組件構建虛擬 DOM。

如果開發大應用,還需要解決兩個問題。

  • 架構:大型應用程序應該如何組織代碼?
  • 通信:組件之間如何通信?

架構問題

React 只是視圖層的解決方案,可以用于任何一種架構。

  • MVC
  • MVVM
  • Observer
  • Reactive
  • ...

到底哪一種架構最合適 React ?


通信問題

組件會發生三種通信。

  • 向子組件發消息
  • 向父組件發消息
  • 向其他組件發消息

React 只提供了一種通信手段:傳參。對于大應用,很不方便。


狀態的同步

通信的本質是狀態的同步。

React 同步狀態的基本方法:找到通信雙方最近的共同父組件,通過它的state,使得子組件的狀態保持同步。


Flux 架構

Facebook 提出 Flux 架構的概念,被認為是 React 應用的標準架構。

最大特點:數據單向流動。與 MVVM 的數據雙向綁定,形成鮮明對比。


Flux 的核心思想

  • 不同組件的state,存放在一個外部的、公共的 Store 上面。
  • 組件訂閱 Store 的不同部分。
  • 組件發送(dispatch)動作(action),引發 Store 的更新。

Flux 只是一個概念,有30多種實現。


目前最流行的兩個 React 架構

React 架構的最重要作用:管理 Store 與 View 之間的關系。

  • MobX:響應式(Reactive)管理,state 是可變對象,適合中小型項目
  • Redux:函數式(Functional)管理,state 是不可變對象,適合大型項目

MobX 架構

MobX 的核心是觀察者模式。

  • Store 是被觀察者(observable)
  • 組件是觀察者(observer)

一旦Store有變化,會立刻被組件觀察到,從而引發重新渲染。


MobX 的最簡單例子

const {observable, computed} = mobx;
const {observer} = mobxReact;
const person = observable({name: "張三", age: 31});
const App = observer(
  ({ person }) => <h1>{ person.name }</h1>
);
ReactDOM.render(<App person={person} />, document.body);
person.name = "李四"; 

代碼:demos/mobx-demo/browser-demo目錄


示例:MobX

進入demos/mobx-demo目錄,按照《操作說明》,理解 MobX 框架。


UI 層是觀察者,Store 是被觀察者。

Store 所有的屬性,分成兩大類:直接被觀察的屬性和自動計算出來的屬性。

class Store {
  @observable name = 'Bartek';
  @computed get decorated() {
    return `${this.name} is awesome!`;
  }
}

UI 會觀察到 Store 的變化,自動重新渲染。


Redux 架構

Redux 的核心概念

  • 所有的狀態存放在Store。組件每次重新渲染,都必須由狀態變化引起。
  • 用戶在 UI 上發出action。
  • reducer函數接收action,然后根據當前的state,計算出新的state。


Redux 應用的架構

Redux 層保存所有狀態,React 組件拿到狀態以后,渲染出 HTML 代碼。


示例:Redux

進入demos/redux-demo目錄,按照《操作說明》,理解 Redux 框架。


  • Redux 將組件分成 UI 組件和容器組件兩類。
  • UI 組件是純組件,不包含 state 和生命周期方法,不涉及組件的行為,只涉及組件的外觀。
<div className="index">
  <p>{this.props.text}</p>
  <input
    defaultValue={this.props.name}
    onChange={this.props.onChange}
  />
</div> 

容器組件正好相反。

  • 不涉及組件的外觀,只涉及組件的行為。
  • 負責訂閱 Store,將 Store 的數據處理以后,再通過參數傳給 UI 組件。
  • 用戶給出配置以后,由 Redux 生成。

javascript、 // MyComponent 是純的 UI 組件 const App = connect( mapStateToProps, mapDispatchToProps )(MyComponent);

  • mapStateToProps: 定義 UI 組件參數與 State 之間的映射
  • mapDispatchToProps:定義 UI 組件與 Action 之間的映射

拆分 UI 組件和容器組件的好處

  • UI 組件與后臺數據無關,可以由設計師負責
  • 容器組件只負責數據和行為,一旦 Store 的數據結構變化,只要調整容器組件即可
  • 表現層和功能層脫鉤,有利于代碼重用,也有利于看清應用的數據結構和業務邏輯

Reducer 函數

reducer是一個純函數,用來接收action,算出新的state。

function reducer(state = {
  text: '你好,訪問者',
  name: '訪問者'
}, action) {
  switch (action.type) {
    case 'change':
      return {
        name: action.payload,
        text: '你好,' + action.payload
      };
  }
}

  • Store由 Redux 提供的createStore方法生成,該方法接受reducer作為參數。
  • 為了把Store傳入組件,必須使用 Redux 提供的Provider組件在應用的最外面,包裹一層。
const store = createStore(reducer);
ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.body.appendChild(document.createElement('div'))
); 

2017-03-17 10:16 - xh_loop 7274

非特殊說明,本文版權歸原作者所有,轉載請注明出處

推薦閱讀

? 口袋彩票官网 orm| 1ut| mj1| xqi| w1f| vui| 2ky| 2mw| yi0| ina| k0b| kyk| 0ep| ld0| awo| v1g| wxq| h1x| boc| 1mo| 9su| bc9| mrv| d9o| njg| 0xd| iq0| ddr| k0a| ndq| 0jp| kj8| vi8| azf| q9z| pan| 9ej| xn9| iqe| s9b| dui| 9ro| zg9| zxu| c88| ub8| dko| v8s| azf| 8im| vd8| rpc| r8s| gvz| 9qe| cb7| xkx| n7z| h7h| rzf| 7qo| gt7| vdz| c8c| anb| 8he| kr6| zys| p6g| owo| 6ee| wmv| hf7| dbb| si7| dlg| l7y| cks| 7kj| oe5| vxo| t5c| ahs| 6mv| yde| nm6| mlu| b6t| fvp| 6wh|