1. 程式人生 > >淺談react中父子元件相互通訊及ref的用法

淺談react中父子元件相互通訊及ref的用法

react的介紹

  1. 宣告式設計 −React採用聲明範式,可以輕鬆描述應用。
  2. 高效 −React通過對DOM的模擬,最大限度地減少與DOM的互動。
  3. 靈活 −React可以與已知的庫或框架很好地配合。
  4. JSX − JSX 是 JavaScript 語法的擴充套件。React 開發不一定使用 JSX ,但我們建議使用它。
  5. 元件 − 通過 React 構建元件,使得程式碼更加容易得到複用,能夠很好的應用在大專案的開發中。
  6. 單向響應的資料流 − React 實現了單向響應的資料流,從而減少了重複程式碼,這也是它為什麼比傳統資料繫結更簡單。
  7. 擁有豐富的元件庫,通過引入完成自身需求

react資料流

這裡主要講解下父子元件之間的通訊,可以說react中的開發者主要注意力在於處理資料,由父元件向下傳遞的props及當前記錄元件的state都為了能實現資料流而服務,好了廢話不多話,用一段簡單的例子來說明:

首先根目錄下的App.js

import React, { Component } from 'react';
import ControlPanel from './controlPanel'
import './App.css';

class App extends Component {
  render() {
    return (
      <div style={{margin: '30px'}} className="App">
        <ControlPanel/>
      </div>
    );
  }
}

export default App;

ControlPanel.js

import React, { Component } from 'react';

class ControlPanel extends Component {
  constructor (props) {
    super(props);
    this.getSum = this.getSum.bind(this);
    this.change = this.change.bind(this);
    this.state = {
      sum: 30,
      text: '父元件預設狀態',
    }
  }
  getSum (count,oldCount) {
    console.log(this);
    let Increment = count - oldCount;
    this.setState({
      sum: this.state.sum + Increment,
    })
  }

  change (t) {
    console.log(t);
    this.setState({
      text: t,
    })
  }

  render () {
    return (
      <div>
        <Counter onChange={this.change} onUpdate={this.getSum} caption="First" initValue={0} />
        <Counter onUpdate={this.getSum} caption="Second" initValue={10} />
        <Counter onUpdate={this.getSum} caption="Third" initValue={20} />
        <h3 style={{ marginTop: '30px' }}>sum: {this.state.sum}</h3>
        <h3 style={{ marginTop: '30px' }}>sum: {this.state.text}</h3>
      </div>
    );
  }
}

class Counter extends Component {
  constructor (props) {
    super(props);
    this.add = this.add.bind(this);
    this.less = this.less.bind(this);
    this.state = {
      count: props.initValue,
    }
  }

  shouldComponentUpdate (nextProp,nextState) {
    if(nextState.count === this.state.count){
      return false;
    }
    return true;
  }

  add () {
    this.trigger(true);
  }

  less () {
    this.trigger(false);
  }

  trigger (action) {
   let num = action?this.state.count + 1:this.state.count - 1;
	   this.setState({
	   count: num,
   });
    this.props.onUpdate(num,this.state.count);
    if(this.props.onChange){
      this.props.onChange('父元件被更新了');
    }
  }

  render () {
    let { caption } = this.props;
    return (
      <div style={{marginTop: '30px'}}>
        <button onClick={this.add} style={{ color: "red", marginRight: '5px' }}>+</button>
        <button onClick={this.less} style={{ color: "blue", marginRight: '5px' }}>-</button>
        <span>{caption} count:{this.state.count}</span>
      </div>
    );
  }
}

export default ControlPanel;

這是個簡單的3個單獨元件的加減法,和一個求和的功能,看起來簡單卻包含了每個單獨元件狀態的管理以及父元件的求和,其中可以體會到react狀態的改變引發view層如何更新及這種單獨管理狀態有何缺點,我會把這裡小例子上傳到GitHub上,有興趣的可以下來試試,後期可能還會用到這個例子改造成redux管理狀態。

程式碼講解

下面是效果

在這裡插入圖片描述

可以看出,ControlPanel 為父元件,父元件下每一個count為一個單獨的元件,而First count,Secondcount,Thirdcount這三個存在相似性,起名為Counter(後面都叫子元件),每個子元件下都有兩個操作,+- 對應後面有記錄,sum為記錄3個子元件數字之和,看下程式碼

<button onClick={this.add} style={{ color: "red", marginRight: '5px' }}>+</button>
<button onClick={this.less} style={{ color: "blue", marginRight: '5px' }}>-</button>

button分別對應add和less兩個方法,通過這方法呼叫setstate分別記錄各自子元件的狀態,如何通知父元件呢?

一種辦法是當子元件狀態發生改變後,呼叫一個方法,該方法在父元件內定義,通過props傳遞給子元件,例如程式碼中的onUpdate,然後父元件的也記錄一個state標記為總數

另一種為父元件拿到子元件的例項

  render () {
    return (
      <div>
        <Counter ref={(ref) => { this.first = ref;}} onChange={this.change} onUpdate={this.getSum} caption="First" initValue={0} />
        <Counter ref={(ref) => { this.Second= ref;}} onUpdate={this.getSum} caption="Second" initValue={10} />
        <Counter ref={(ref) => { this.Third= ref;}} onUpdate={this.getSum} caption="Third" initValue={20} />
        <h3 style={{ marginTop: '30px' }}>sum: {this.state.sum}</h3>
        <h3 style={{ marginTop: '30px' }}>sum: {this.state.text}</h3>
      </div>
    );
  }

如上圖修改後程式碼,ref接受一個回撥函式,第一個引數為當前元件的例項,將其繫結在父元件上,這樣可以實時監聽子元件的變化。

缺點

這種狀態的管理缺點很明顯,父子元件都管理著自己的狀態,如果出現某種其外情況導致,子元件未能及時通知到父元件的話,將導致出現bug,對於大型專案來說這種情況是很容易出現的,redux的出現解決了這一問題,由於篇幅有限,這裡不再做詳細解釋

本文例子已上傳至GitHub,有興趣的同學可以自己下載試驗 react小例子.