1. 程式人生 > >React.js讀書與總結:《react-tutorial》

React.js讀書與總結:《react-tutorial》

最近接觸的一個專案中使用了React為主要框架,雖然之前也多多少少學過一些React,但是還需要更深入的學習和更熟練的掌握,所以最近我打算好好的讀上幾本React的書,今天帶來第一本書:《react-tutorial》的學習總結。

前言

技術在沒有真正使用之前,沒法評價哪一個好,沒有最好的,只有最合適的。

一 Webpack 配置 React 開發環境

搭建一個現代的前端開發環境配套的工具有很多,比如 Grunt / Gulp / Webpack / Broccoli,
這些都是要解決前端工程化問題。

而ES6 編譯工具 Babel,則內建了對 JSX 語法的支援。

(1)Webpack簡介:

前端資源載入/打包工具,只需簡單的配置就可提供前端工程化需要的各種功能,
如有需要還可被整合到其他如 Grunt / Gulp 的工作流

(2)webpack 的優勢:

  1. 以 commonJS 的形式來書寫指令碼,對 AMD/CMD 的支援也很全面,方便舊專案進行程式碼遷移。
  2. 能被模組化的不僅僅是 JS 。
  3. 開發便捷,能替代部分 grunt/gulp 的工作,比如打包、壓縮混淆、圖片轉base64等。
  4. 擴充套件性強,外掛機制完善

(3)安裝 Webpack:

npm install -g webpack

使用 webpack.config.js 配置檔案

要編譯 JSX,先安裝對應的 loader: npm install babel-loader –save-dev

(4)webpack配置

module下的loaders 是最關鍵的一塊配置,它告知 webpack 每一種檔案都需要使用什麼載入器來處理。

二 JSX

(1)為什麼要引入 JSX 這種語法?

傳統的 MVC 是將模板放在其他地方,比如 script 標籤或者模板檔案,再在 JS 中通過某種手段引用模板。按這種思路,想想多少次我們面對四處分散的模板片段不知所措?糾結模板引擎,糾結模板存放位置,糾結如何引用模板。

React 認為元件才是王道,而元件是和模板緊密關聯的,元件模板和元件邏輯分離讓問題複雜化了。所以就有了 JSX 這種語法,就是為了把 HTML 模板直接嵌入到 JS 程式碼裡面,這樣就做到了模板和元件關聯,但是 JS 不支援這種包含 HTML 的語法,所以需要通過工具將 JSX 編譯輸出成 JS 程式碼才能使用。

(2)JSX基本語法

1.小寫的字串是 HTML 標籤,大寫開頭的變數是 React 元件。

2.HTML 裡的 class 在 JSX 裡要寫成 className,因為 class 在 JS 裡是保留關鍵字。同理某些屬性比如 for 要寫成 htmlFor。

3.表示式
屬性值使用表示式,只要用 {} 替換 “”。

表示式是非常強大的,我們可以使用它在JSX標籤間或屬性中放置js的各種表示式或函式實現各種功能。

子元件也可以作為表示式使用,如:

// Input (JSX):
var content = <Container>{window.isLoggedIn ? <Nav /> : <Login />}</Container>;
// Output (JS):
var content = React.createElement(
  Container,
  null,
  window.isLoggedIn ? React.createElement(Nav) : React.createElement(Login)
);

4.JSX註釋:
在< >內部可使用js的註釋,如果在一個元件的子元素位置使用註釋要用 {} 包起來。

5.自定義 HTML 屬性:
如果在 JSX 中使用的屬性不存在於 HTML 的規範中,這個屬性會被忽略。如果要使用自定義屬性,可以用 data- 字首。

6.屬性擴散:
使用es6的寫法,可給元件設定多個屬性,如:

var props = {};
props.foo = x;
props.bar = y;
var component = <Component {...props} />;
props 物件的屬性會被設定成 Component 的屬性。

另外,jsx中:
style 屬性接受由 CSS 屬性構成的 JS 物件
onChange 事件表現更接近我們的直覺(不需要 onBlur 去觸發)

(3)元件

元件的兩個核心概念:props和state。

1.props

props 即元件的屬性,由外部通過 JSX 屬性傳入設定,一旦初始設定完成,就可以認為 this.props 是不可更改的,所以不要輕易更改設定 this.props 裡面的值(雖然對於一個 JS 物件你可以做任何事)。

2.state
state 即元件的當前狀態,可以把元件簡單看成一個“狀態機”,
根據狀態 state 呈現不同的 UI 展示。一旦狀態(資料)更改,元件就會自動呼叫 render 重新渲染 UI,這個更改的動作會通過 this.setState()來觸發。

劃分狀態的原則:讓元件儘可能地少狀態,便於元件易維護。

當更改某個資料需要更新元件 UI 的就可以認為是 state。

3.無狀態元件

也可以用純粹的函式定義無狀態元件(沒有狀態和生命週期,只簡單的接受 props 渲染生成 DOM 結構)。

無狀態元件非常簡單,開銷低,可能的話儘量去使用無狀態元件。比如使用箭頭函式定義

const HelloMessage = (props) => <div> Hello {props.name}</div>;
render(<HelloMessage name="John" />, mountNode);

因為無狀態元件只是函式,沒有例項返回,這點在想用 refs 獲取無狀態元件的時候要注意。

4.元件生命週期

1.初始化 this.state 的值,只在元件載入之前呼叫一次。

ES6中可以在建構函式中初始化狀態,如:

class Counter extends Component {
  constructor(props) {
    super(props);
    this.state = { count: props.initialCount };
  }

  render() {
    // ...
  }
}

2.載入(渲染)元件觸發的生命週期函式:

componentWillMount()
只在載入之前呼叫,在 render 之前呼叫,可以在這個方法裡面呼叫 setState 改變狀態,並且不會導致額外呼叫一次 render

componentDidMount()
只在載入完成之後呼叫,在 render 之後呼叫,從這裡開始可以通過 ReactDOM.findDOMNode(this) 獲取到元件的 DOM 節點。

3.更新(重新渲染)元件觸發的生命週期函式:

這些方法不會在首次 render 元件的週期呼叫。

componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
componentDidUpdate

4.解除安裝元件觸發的生命週期函式:

componentWillUnmount

(4)React事件處理

1.繫結事件

例:


...

handleClick(e) {
    this.setState({ liked: !this.state.liked });
  }

  render() {
    const text = this.state.liked ? 'like' : 'haven\'t liked';
    return (
      <p onClick={this.handleClick.bind(this)}>
          You {text} this. Click to toggle.
      </p>
    );
  }

...

React 裡面繫結事件的方式和在 HTML 中繫結事件類似,使用駝峰式命名指定要繫結的事件型別(比如 onClick)屬性為元件定義的一個方法如( {this.handleClick.bind(this)} )。

注意要顯式呼叫 bind(this) 將事件函式上下文繫結要元件例項上,這也是 React 推崇的原則:儘量使用顯式的容易理解的js程式碼

2.合成事件和原生事件

React 實現了一個“合成事件”層,這個事件模型保證了和 W3C 標準保持一致,“合成事件”提供了額外的好處:事件委託。

“合成事件”會以事件委託的方式繫結到元件最上層,並且在元件解除安裝(unmount)的時候自動銷燬繫結的事件。

原生事件:比如在 componentDidMount 方法裡面通過 addEventListener 繫結的事件就是瀏覽器原生事件。

所有通過 JSX 方式繫結的事件都是繫結到“合成事件”,建議都使用 React 的方式處理事件。

3.給事件處理函式傳遞引數

方法:bind(this, arg1, arg2, …)

例:

render: function() {
    return <p onClick={this.handleClick.bind(this, 'extra param')}>;
},
handleClick: function(param, event) {
    // handle click
}

(5)DOM 操作

大部分情況下不需要通過查詢 DOM 元素去更新元件的 UI,只要關注設定元件的狀態(setState)。可能在某些情況下確實需要直接操作 DOM。

ReactDOM.render 元件返回的是對元件的引用,也就是元件例項(對於無狀態狀態元件來說返回 null),注意 JSX 返回的不是元件例項,它只是一個 ReactElement 物件。

例:

// A ReactElement
const myComponent = <MyComponent />

// render
const myComponentInstance = ReactDOM.render(myComponent, mountNode);
myComponentInstance.doSomething();

findDOMNode()

當元件載入到頁面上之後(mounted),都可以通過 react-dom 提供的 findDOMNode() 方法拿到元件對應的 DOM 元素。

import { findDOMNode } from 'react-dom';

// Inside Component class
componentDidMound() {
  const el = findDOMNode(this);
}

注意:findDOMNode() 不能用在無狀態元件上。

Refs

另一種方式是通過在要引用的 DOM 元素上面設定一個 ref 屬性指定一個名稱,然後通過 this.refs.name 來訪問對應的 DOM 元素

例:

clearAndFocusInput() {
    this.setState({ userInput: '' }, () => {
      this.refs.theInput.focus(); //2.
    });
  }

  render() {
    return (
      <div>
        <div onClick={this.clearAndFocusInput.bind(this)}>
          Click to Focus and Reset
        </div>
        <input
          ref="theInput" //1.
          value={this.state.userInput}
          onChange={this.handleChange.bind(this)}
        />
      </div>
    );
  }

如果 ref 是設定在原生 HTML 元素上,它拿到的就是 DOM 元素,如果設定在自定義元件上,它拿到的就是元件例項,這時候就需要通過 findDOMNode 來拿到元件的 DOM 元素。

因為無狀態元件沒有例項,所以ref 不能設定在無狀態元件上,如果想要拿無狀態元件的 DOM 元素的時候,就需要用一個狀態元件封裝一層,然後通過 ref 和 findDOMNode 去獲取。

可以使用 ref 到的元件定義的任何公共方法,比如 this.refs.myTypeahead.reset()
Refs 是訪問到元件內部 DOM 節點唯一可靠的方法
Refs 會自動銷燬對子元件的引用(當子元件刪除時)

refs注意:
不要在 render 或者 render 之前訪問 refs
不要濫用 refs,比如只是用它來按照傳統的方式操作介面 UI:找到 DOM -> 更新 DOM

(6)元件間通訊

未完待續

(7)Mixins

未完待續

(8)Redux

React相關參考資料: