React系列---React(二)組件的prop和state

React系列---React(一)初識React
React系列---React(二)組件的prop和state
React系列---React(三)組件的生命週期react


組件是React的基石,全部的React應用程序都是基於組件的。基於組件的應用開發是普遍使用的軟件開發模式,用分而治之的方法,把一個大的應用分解成若干小的組件,每一個組件只關注某個特定功能,可是把組件組合起來,就能構成一個功能龐大的應用。npm

React組件的數據分爲兩種,prop和state,不管prop或者state的改變,均可能引起組件的從新渲染。prop是組件對外接口,state是組件內部狀態。segmentfault

第一個組件

create-react-app工具,初始化一個React項目:數組

npm create-react-app react-component-demo

建立一個能夠計算點擊數的組件:
/src/ClickCounter.js:瀏覽器

import React from 'react';

class ClickCounter extends React.Component {
    constructor(props) {
        super(props);
        this.onClickButton = this.onClickButton.bind(this);
        this.state = {count: 0};
    }

    onClickButton() {
        this.setState({count: this.state.count + 1});
    }

    render() {
        return (
          <div>
            <button onClick={this.onClickButton}>Click Me</button>
            <div>
              Click Count: {this.state.count}
            </div>
          </div>
        );
    };
}

export default ClickCounter;

修改/src/index.js:babel

import React from 'react';
import ReactDOM from 'react-dom';
import ClickCounter from './ClickCounter';

ReactDOM.render(<ClickCounter />, document.getElementById('root'));

運行React項目app

npm run start

clipboard.png

點擊按鈕,數字會隨之增長。恭喜你,已經構建了一個有交互的組件!less

咱們還能夠在React組件中定義樣式。修改ClickCounter組件的render函數:dom

render() {
    const counterStyle = {
        margin: '16px'
    };
    return (
      <div style={counterStyle}>
        <button onClick={this.onClickButton}>Click Me</button>
        <div>
          Click Count: <span id="clickCount">{this.state.count}</span>
        </div>
      </div>
    );
};

組件的prop

React組件經過定義本身可以接受的prop就定義了本身對外公共接口。外部世界經過prop和組件對話。函數

給prop賦值

從外部世界看prop的使用:

<SampleButton id="sample" borderWidth={2} onClick={onButtonClick} style={{color: "red"}} />

上面的例子使用了名爲SampleButton的組件實例。React組件的prop所能支持的類型除了字符串,還能夠是任何一種JavaScript語言支持的數據類型。當prop的類型不是字符串時,再JSX中必須用花括號{}把值包裹,因此style的值有兩層花括號,外層表明是JSX的語法,內層表明這是個對象常量。

React組件要反饋數據給外部世界,也是用prop,由於prop類型也能夠是函數,函數類型的prop等於讓父組件交給子組件一個回調函數,子組件在恰當的時機調用函數的prop,就能夠把信息傳遞給外部世界。

爲了演示,咱們構造一個應用包含兩種組件,ControlPanel父組件,而後若干個Counter子組件。對於Counter組件,父組件ControlPanel就是外部世界:

class ControlPanel extends React.Component {
    render() {
        return (
          <div>
            <Counter caption="First" initValue={0} />
            <Counter caption="Second" initValue={10} />
            <Counter caption="Third" initValue={20} />
          </div>
        );
    }
}

React要求render只能返回一個元素,因此咱們用div包裹了3個子組件。

每一個Counter組件使用了caption和initValue兩個prop。ControlPanel經過caption的prop傳遞給Counter組件實例說明文字,經過initValue的prop傳遞給Count組件一個初始的計數值。

讀取prop值

看下Counter組件內部是如何接收prop的:

class Counter extends React.Component {
    constructor(props) {
        super(props);

        this.onClickIncrementButton = this.onClickIncrementButton.bind(this);
        this.onClickDecrementButton = this.onClickDecrementButton.bind(this);

        this.state = {
            count: props.initValue || 0
        };
    }
}

若是組件須要定義本身的構造函數,構造函數第一行必定要經過super調用父類React.Component的構造函數。給this.props賦值也是React.Component構造函數的工做之一。
在Counter的構造函數中,還給兩個成員函數綁定了當前this的執行環境,由於ES6方式建立的組件並不自動給咱們綁定this到當前實例對象。

在其餘函數中則能夠經過this.props訪問傳入的值,看一下render函數:

render() {
    const {caption} = this.props; // ES6的解構賦值
    return (
      <div>
        <button style={buttonStyle} onClick={this.onClickIncrementButton}>+</button>
        <button style={buttonStyle} onClick={this.onClickDecrementButton}>-</button>
        <span>{caption} count: {this.state.count}</span>
      </div>
    );
};

propTypes檢查

在ES6方法定義的組件中,能夠經過增長類的propTypes屬性來定義prop規格。在運行和靜態代碼檢查時,均可以根據propTypes判斷外部世界是否正確地使用了組件的屬性。

增長Counter組件的propTypes定義:

Counter.propTypes = {
  caption: PropTypes.string.isRequired,
  initValue: PropTypes.number
};

開發過程當中,定義propTypes代碼能夠避免犯錯,可是在發佈產品時,能夠用babel-react-optimize工具自動去除propTypes,這樣部署到產品環境的代碼就會更優。

組件的state

驅動組件渲染的除了prop,還有state,state表明組件內部狀態。因爲React組件禁止修改傳入的prop,因此當組件須要記錄自身的數據變化時,就要使用state。
在Counter組件中,初始計數能夠經過initValue這個prop指定。當用戶點擊「+」和「-」改變計數時,就要Counter組件本身經過state來存儲了。

初始化state

一般在構造函數的結尾處初始化state,就如上面的Counter:

constructor(props) {
    ...
    this.state = {
        count: props.initValue || 0
    };
}

因爲在PropType聲明中沒有用isRequired,咱們須要在代碼中判斷給定的prop值是否存在,不存在則給一個默認值。咱們能夠利用React的defaultProps功能,避免判斷邏輯這種充斥在構造函數之中,讓代碼更優。

給Counter組件添加defaultProps代碼:

Counter.defaultProps = {
    initValue: 0
};

構造函數就能夠簡化了:

constructor(props) {
    ...
    this.state = {
        count: props.initValue
    };
}

讀取和更新state

經過給button的onClick屬性掛載點擊事件處理函數,咱們能夠改變組件的state,以點擊「+」按鈕的響應函數爲例:

onClickIncrementButton() {
    this.setState({count: this.state.count + 1});
}

經過this.state能夠讀取到組件的當前state。注意的是,改變state必須使用this.setState函數,而不能直接修改this.state。若是你違反這個操做,瀏覽器Console會告警。

直接修改this.state的值,只是野蠻的修改了state,卻沒有驅動組件從新渲染,新的值固然也不會反應在界面上。而this.setState()函數所作的事情,就是改變this.state的值後再驅動組件從新渲染。

無狀態函數式組件

沒有內部state,不須要組件生命週期函數。能夠用純函數的形式來表達。它作的事情只是根據輸入來展現組件,沒有其餘反作用。能夠把這種組件稱爲無狀態函數式組件(stateless functional component)。

import React from 'react';

// 用一個純函數表示
const Hobby = (props) => <li>{props.hobby}</li>;

export default Hobby;

state設計原則

建立儘可能多的無狀態組件,這些組件惟一關心的就是渲染數據。而在最外層,應該有一個包含state的父級別組件,用於處理各類事件、交流邏輯、修改state。對應的子組件要關心的只是傳入的屬性而已。

state應該包含組件的事件回調函數可能引起UI更新的這類數據。在實際的項目中,應該是輕量化的JSON數據,儘可能把數據的表現設計到最小,更多的數據能夠在render中經過各類計算獲得。

prop和state對比

  • prop用於定義外部接口,state用於記錄內部狀態;
  • prop的賦值在外部世界使用組件時,state的賦值在組件內部;
  • 組件不該該改變prop的值,而state的存在的目的就是讓組件來改變的。

DOM操做

大多數狀況下,不須要操做DOM去更新UI,應使用setState。可是有些狀況確實須要訪問一些DOM(如表單的值),那麼可採用refs方式來得到DOM節點。只須要加個ref屬性,而後經過this.refs.name來得到對應的DOM結構。

示例Profile組件:

render() {
  return (
    <div>
      ...
      <input type="text" ref="hobby" />
      <button onClick={this.addHobbyCallback}>添加愛好</button>
    </div>
  )
}

在button上添加事件,取得input的值,添加到state的值裏面:

addHobbyCallback() {
  // 用this.refs.name來取得DOM節點
  let hobbyInput = this.refs.hobby;
  let val = hobbyInput.value;
  if (val) {
    let hobbies = this.state.hobbies;
    // 添加值到數組
    hobbies = [...hobbies, val];
    // 更新state, 刷新UI
    this.setState({
      hobbies
    }, () => {
      hobbyInput.value = '';
    });
  }
}

React系列---React(一)初識React
React系列---React(二)組件的prop和state
React系列---React(三)組件的生命週期

相關文章
相關標籤/搜索