[ 筆記 ] React 03 - Functional Componet & Component 之間的溝通


Posted by krebikshaw on 2020-10-20

Functional Componet

之前用的 Component 都是用 class 的形式來寫 ( Class Component ),而其實有另外一種方式寫 Component,叫做 functional Component。

以下是 Counter 這個 Component 用不同形式來寫:

/* Class Component */
class Counter extends Component {
  render() {
    console.log('Counter-render');
    return <div>{this.props.number}</div>;
  }
}

/* Functional Component */
function Counter(props) { // => 一樣有 props 的屬性可以使用
  return <div>{props.number}</div>
}

/* Functional Component - 或是更進階一點,使用解構語法 */
function Counter({number}) { // => 其實就是 const {number} = props
  return <div>{number}</div>
}

Class Component 跟 Functional Component 的差異

當你只是要寫個很單純的 Component,不需要儲存 state 也沒有其他事件監聽,功能只有 render 畫面時,就很適合用 Functional Component,因為語法比起 Class Component 會比較簡潔一點。

Component 之間的溝通方式

在 React 裡面,children Component 沒有辦法改變 parent Component 的 state,所以最好的方式是把 parent 改變 state 的 function 傳下去給 children,當成其中一個 props 的屬性,讓 children Component 透過 parent Component 自己的 function 來改變自己的資料。

什麼意思?
假設有位老師代表著 parent Component,老師有一把鑰匙可以開教室的門,我們可以視作只有老師可以執行「開教室門」這個動作。而有一位學生代表著 children Component。當老師想請同學幫忙開教室門的時候,因為同學並沒有辦法執行「開教室門」這個動作,所以老師需要把自己的鑰匙交到學生手上,使同學能夠借助老師的「開教室門」這個動作來開門。

所以 children Component 如果要改變 parent Component 的 state,就要呼叫 parent Component 傳下來的方法,呼叫那個方法讓 parent Component 自己去改變自己的 state。

const Title = (props) => {
  return (
    // => 接收到 App 傳來的 handleClick,才能藉此改變 App 的 state
    <h1 onClick={props.handleClick}>{props.text}</h1>
  )
}

class App extends Component {
  constructor() {
    super();
    this.state = {
      counter : 1
    }

    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    this.setState({
      counter: this.state.counter + 1
    })
  }
  render() {
    return (
      <div>
        // => 把能夠改變 state 的 handleClick 傳給 Title
        <Title handleClick={this.handleClick} text={this.state.counter}/>
      </div>
    )
  }
}

步步拆解以上的流程解析:

  • Title
    • render Title props.text => App's state.counter: 1
    • props.handleClick => App.handleClick: func
  • Trigger Title => h1 => onClick => props.handleClick => App.handleClick
  • App.handleClick => setState => counter : 2
  • App state changed => re-render
  • render Title props.text => App's state.counter: 2

把上面範例改寫成「 每點一次,counter 就變成一個隨機數 」,示範傳進去的 function 有帶參數的例子,變成很像在寫 callback function:

const Title = (props) => {
  return (
    <h1 onClick={() => {
      props.changeCounter(Math.random()) // => 就像一個 callback function 的寫法
    }}>{props.text}</h1>
  )
}

class App extends Component {
  constructor() {
    super();
    this.state = {
      counter : 1
    }

    this.changeCounter = this.changeCounter.bind(this); // => 不要忘了 bind
  }

  changeCounter(num) {
    this.setState({
      counter: num
    })
  }
  render() {
    return (
      <div>
         // => 一樣把能夠改變 App state 的 function 傳進去
        <Title changeCounter={this.changeCounter}  text={this.state.counter}/>
      </div>
    )
  }
}

小記

  • children 必須透過 parent 傳進來的 function 來改變 props
  • 要記住的重要觀念就是,只有 Component 可以改變自己的 state,如果要改變其他 Component 的 state ,只有該 Component 有提供的方法才可行。

#Functional Comnent







Related Posts

[ JavaScript 09 ] String 類型的內建函式

[ JavaScript 09 ] String 類型的內建函式

550. Game Play Analysis IV

550. Game Play Analysis IV

MTR04_0914

MTR04_0914


Comments