[ 筆記 ] 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

Bicycle Kinematic Model 實作小筆記

Bicycle Kinematic Model 實作小筆記

Promise 筆記

Promise 筆記

How to build CICD with Jenkins as code based on container

How to build CICD with Jenkins as code based on container


Comments