Yakim shu Hi, 這是我擴充腦內海馬體的地方。

[第二十一週] React 基礎:Functional Componet & 父子 Component 之間的溝通

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 時要怎麼決定用哪種寫法呢?

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


父子 Component 之間的溝通方式

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

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>
    )
  }
}

此時不斷得點擊 <h1> 就可以看到數字增加。

codepen 範例

See the Pen [React] change state by props by Yakim Shu (@yakim-shu) on CodePen.

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

結論: children 必須透過 parent 傳進來的 function 來改變 props

所以重點是當 children Component <Title /> 要更新傳遞進來的 props 時,是沒有辦法直接對 props 做更改的,必須透過 parent Component <App /> 傳遞進來的 function 做更新才行。


props function 帶參數的寫法

把剛剛的範例改寫成「 每點一次,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>
    )
  }
}

codepen 範例

See the Pen [React] change state with random number by props by Yakim Shu (@yakim-shu) on CodePen.

結論

所以要記住的重要觀念就是,只有 Component 可以改變自己的 state,如果要改變其他 Component 的 state ,只有該 Component 有提供的方法才可行。


( 以上內容大部分是 程式導師實驗計畫第三期 的學習筆記,如有錯誤歡迎糾正,非常感謝 🤓 )