iT邦幫忙

2021 iThome 鐵人賽

DAY 14
0
Modern Web

<法式Terrine : React next.js Chakra-UI styled-component 精緻的搭配>系列 第 14

< 關於 React: 開始打地基| 父組件、子組件、兄弟姐妹組件的關係 >

09-14-2021

本章內容
  • 子組件更新父組件的狀態
    • 設定組建間的狀態
    • 設定組建間事件處理的程序
  • 子組件更新其他兄弟姐妹的傳遞方式
    • 確認子組件們之間的引用
    • 組件分工的方式
    • 將顯示傳遞給兄弟姐妹組件
  • 結論
    • 無狀態component繼承有狀態component回顧

子組件更新父組件的狀態

設定組建間的狀態

首先我們要先知道我們需要在子組件更改的位置並且定義。
是在line10``<h1> Hey my name is {this.props.name}! </h1>
下拉選單選擇了顯示的項目value會返回給name顯示

// Child.js
import React from 'react';

export class Child extends React.Component {
  render() {
    return (
      <div>
        <h1>
          Hey there, I'am {this.props.name}!
        </h1>
        <select id="great-names">
          <option value="Frarthur">
            Frarthur
          </option>

          <option value="Gromulus">
            Gromulus
          </option>

          <option value="Thinkpiece">
            Thinkpiece
          </option>
        </select>
      </div>
    );
  }
}

在父組件中,我們需要先import<Child/>component到頁面中。
並且使用setState()定義一個狀態的事件。

// Parent.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Child } from './Child';

class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {name:'Frarthur'};
  }

  changeName(newName){
    this.setState({
      name:newName
    });
  }

  render() {
    return <Child name={this.state.name} />
  }
}

ReactDOM.render(
	<Parent />,
	document.getElementById('app')
);

設定組件間事件處理的程序

以上是狀態的設置可以將監聽事件傳遞下去了,接著是要傳遞事件處理的方式。
bind this changeName()在constructor裡面,把函式傳遞下去給子組件,而要在傳遞的component上使用onChange把要傳遞的方法寫上去

// Parent.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Child } from './Child';

class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {name:'Frarthur'};
    this.changeName = this.changeName.bind(this);
  }

  changeName(newName){
    this.setState({
      name:newName
    });
  }

  render() {
    return <Child name={this.state.name} onChange={ this.changeName } />
  }
}

ReactDOM.render(
	<Parent />,
	document.getElementById('app')
);

我們使用props傳遞方法下來子層,理當會先在需要改變的<select>上放上接props的方式onChange(this.props.onChange)

但我們少了傳遞props的橋樑,以及需要傳遞的參數,因為這不會傳遞一個名稱,而是會傳遞一個事件的物件,所以這個函數應該要接收一個event object作為參數,才可以調用這個函式。

handleChange(e) {
  const name = e.target.value;
  this.props.onChange(name);
}

stateless component 綁定方式

// Child.js

export class Child extends React.Component {
 constructor(props) {
  super(props);
  this.handleChange = this.handleChange.bind(this);
}
  handleChange(e) {
  const name = e.target.value;
  this.props.onChange(name);
}
 
  render() {
    return (
      <div>
        <h1 >
          Hey my name is {this.props.name}!
        </h1>
        <select id="great-names" onChange={this.handleChange}>
          <option value="Frarthur">
            Frarthur
          </option>

子組件更新其他兄弟姐妹的傳遞方式

  • <Child / ><sibling /> 兩個compoents

確認子組件們之間的引用

首先,確認import了<sibling />這個component在頁面上,以及在return時有把<sibling / >放進來,最後確認與<Child />,使用同一個外層包裝起來的<div></div>

組件分工的方式

<sibling/ > 的主要工作是顯示選擇的名稱,name={this.state.name}要顯示的name是存在Parents中的state,所以可以透過名稱傳遞給sibling並且顯示。
同時<Child/>的工作是提供更改所選名稱的方法,而不是==顯示==,所以我們把原本的onChange()與顯示的name都從Parents移除

將顯示傳遞給兄弟姐妹組件

我們現在已經將<sibling/>作為prop傳遞了。
所以我們要在prop顯示要傳遞的name
<sibling/> 中,宣告一個新的變數name,讓變數等於prop傳遞的name,將文句中要替換的名稱改為變數,name

// parent.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Child } from './Child';
import { Sibling } from './Sibling';
// 引入子組件

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

    this.state = { name: 'Frarthur' };
    // 預設要顯示的名稱
    this.changeName = this.changeName.bind(this);
    // 綁定要更改的方法
  }

// 更改的方法
  changeName(newName) {
    this.setState({
      name: newName
    });
  }

  render() {
    return (
      <div>
        // <Child 
        //   name={this.state.name} 
        //   onChange={this.changeName} />
        // 將原本在一個component中要做的事情分給兄弟姐妹執行
        <Child onChange={this.changeName} />
        // 負責更改名稱的方式
        <Sibling name={this.state.name} />
        // 負責更改狀態要顯示的名字
      </div>
    );
  }
}

ReactDOM.render(
  <Parent />,
  document.getElementById('app')
);

// Child.js
import React from 'react';

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

    this.handleChange = this.handleChange.bind(this);
    // 綁定更改的方法
  }

// 選擇到的value傳到方法中
  handleChange(e) {
    const name = e.target.value;
    this.props.onChange(name);
  }

  render() {
    return (
      <div>
        <select
          id="great-names"
          onChange={this.handleChange}>

          <option value="Frarthur">Frarthur</option>
          <option value="Gromulus">Gromulus</option>
          <option value="Thinkpiece">Thinkpiece</option>
        </select>
      </div>
    );
  }
}
// sibling.js
import React from 'react';

export class Sibling extends React.Component {
  render() {
  const name =  this.props.name
// 設定變數接傳遞的過來的`name`
    return (
      // <div>
      //   <h1>Hey, my name is Frarthur!</h1>
      //   <h2>Don't you think Frarthur is the prettiest name ever?</h2>
      //   <h2>Sure am glad that my parents picked Frarthur!</h2>
      // </div>
    // 原本的標題內容都只能出現一個名稱,用變數{name}呈現就會改變名字了!
      <div>
        <h1>Hey, my name is {name}!</h1>
        <h2>Don't you think {name} is the prettiest name ever?</h2>
        <h2>Sure am glad that my parents picked {name}!</h2>
      </div>
    );
  }
}

結論:

無狀態component繼承有狀態component回顧:

  1. 在parent中定義了一個狀態的function:this.state
    changeName(newName) { this.setState({ name: newName }); }

  2. 有狀態的component將function往下傳遞給無狀態的component
    <Child onChange={this.changeName} />

  3. 這個無狀態的class function定義了傳遞函數,這個傳遞函數可以做為參數使用
    <Child /> handleChange(e) { const name = e.target.value; this.props.onChange(name); }

  4. 這個無狀態組件的componet使用了一個新的方程式當作事件程序
    <Child /> onChange={this.handleChange}>

  5. 當事件發生了改變,parent 的 state狀態更新時(選擇了下拉選單)

  6. 這個有狀態的component就會把狀態往下傳遞給無狀態component,這與改變state的方式不同
    <Sibling name={this.state.name} />

  7. 無狀態componet class(sibling) 接收到了state 於是就顯示它
    <sibling/> const name = this.props.name;

  8. 總的來說,有狀態的component只負責render,<Child/ >負責state,負責顯示切換的state


上一篇
< 關於 React: 開始打地基| 表單內的顯示元素,map() ShowAdd 與Key >
下一篇
< 關於 next.js: 開始打地基| Next中的Pages,究竟有什麼用途? >
系列文
<法式Terrine : React next.js Chakra-UI styled-component 精緻的搭配>18

尚未有邦友留言

立即登入留言