React 元件通訊

尤加利葉發表於2021-01-03

目錄

元件通訊

元件的Props

元件通訊的三種方式

父元件傳遞資料給子元件

子元件傳遞資料給父元件

兄弟元件

Context

props 深入

children 屬性

props 效驗

 使用步驟

約束規則

props的預設值


元件通訊

元件是獨立且封閉的單元 , 預設情況下 ,  只能使用元件自己的資料 . 在元件化過程中 , 我們將一個完整的功能拆分成多個元件 , 以更好地完成整個應用的功能 . 而在這個過程中 , 多個元件之間不可避免的要共享某些資料 . 為了實現這些功能 ,  就需要打破元件的獨立封閉性 , 讓其與外界溝通 . 這個過程就是元件通訊 

元件的Props

  • 元件是封閉的 ,  要接受外部資料應該通過 props 來實現
  • props的作用: 接收傳遞給元件的資料
  • 傳遞資料: 給元件標籤新增屬性
  • 接收資料: 函式元件通過引數props接收資料 , 類元件通過 this.props 接收資料
<Hello name="jack" age={ 19 } />
// 函式元件 
function Hello(props) {
  console.log(props);
  return (
    <div>接收到資料:{props.name}</div>
  )
}
ReactDOM.render(<Hello name='zs' age={19} />, document.getElementById('root'))
// 類元件
class Hello extends React.Component {
  render() {
    return (
      <div>接收到的資料:{this.props.age}</div>
    )
  }
}
ReactDOM.render(<Hello name='zs' age={19} />, document.getElementById('root'))

特點

  1. 可以給元件傳遞任意型別的資料
  2. props 只讀的物件 , 只能讀取屬性的值 , 無法修改物件
  3. 注意: 使用類元件時候 , 如果寫了建構函式 , 應該將props 傳遞給 super() , 否則 , 無法在建構函式中獲取到props

class Hello extends React.Component {
  constructor(props) {
    super(props)
    console.log(this.props);
  }
  render() {
    return (
      <div>接收到的資料:{this.props.age}</div>
    )
  }
}
ReactDOM.render(<Hello name='zs' age={19} />, document.getElementById('root'))

元件通訊的三種方式

 元件之間的通訊分為3種:

  1. 父元件   =>  子元件
  2. 子元件   =>  父元件
  3. 兄弟元件

父元件傳遞資料給子元件

  1. 父元件提供要傳遞的state資料
  2. 給子元件標籤新增屬性 , 值為 state 中的資料
  3. 子元件中通過 props 接受父元件中傳遞的資料
// 父元件  =>  子元件
// 父元件 
class Parent extends React.Component {
  state = { lastName: '吳' }
  render() {
    return (
      <div>
        傳遞資料給子元件:<Child name={this.state.lastName} />
      </div>
    )
  }
}

//子元件
function Child(props) {
  return <div>子元件收到資料:{props.name}</div>
}

子元件傳遞資料給父元件

思路: 利用回撥函式 , 父元件提供回撥 , 子元件呼叫 , 將要傳遞的資料作為回撥函式的引數

  1. 父元件提供一個回撥函式( 用於接收資料 )
  2. 將該函式作為屬性的值 , 傳遞給子元件
  3. 子元件通過 props 呼叫回撥函式
  4. 將子元件的資料作為引數傳遞給回撥函式
// 父元件
class Parent extends React.Component {
  getChildMsg = (data) => {
    console.log('接收到子元件資料', data);
  }
  render() {
    return (
      <div className="parent">
        父元件:<Child getMsg={this.getChildMsg} />
      </div>
    )
  }
}

//子元件
class Child extends React.Component {
  state = { ChildMsg: "React" }
  handleClick = () => {
    this.props.getMsg(this.state.ChildMsg)
  }
  render() {
    return (
      <button onClick={this.handleClick}>給父元件傳值</button>
    )
  }
}


ReactDOM.render(<Parent name='zs' age={19} />, document.getElementById('root'))   

注意: 回撥函式中 this 指向問題 

兄弟元件

  • 共享狀態 提升到最近的公共父元件中 , 由公共父元件管理這個狀態
  • 思想: 狀態提升
  • 公共父元件職責
    • 提升共享狀態
    • 提供操作共享狀態的方法
  • 要通訊的子元件只需通過 props 接收狀態或操作狀態的方法
// 父元件
class Counter extends React.Component {
  // 提供共享狀態
  state = {
    count: 0
  }
  // 提供修改狀態的方法
  onIncrement = (data) => {
    this.setState({
      count: this.state.count + data
    })
  }
  render() {
    return (
      <div>
        <Child1 count={this.state.count} />
        <Child2 getData={this.onIncrement} />
      </div>
    )
  }
}

// 子元件
const Child1 = (props) => {
  return <h1>計數器:{props.count}</h1>
}

// 子元件
const Child2 = (props) => {
  return <button onClick={() => props.getData(1)}>+1</button>
}
ReactDOM.render(<Counter />, document.getElementById('root'))   

Context

如果APP元件要傳遞資料給Child元件,應該怎麼處理
  • 處理方式: 使用 props 一層層元件往下傳遞 ( 繁瑣 )
  • 更好的姿勢: 使用 Context 
    • 作用: 跨元件傳遞資料 ( 比如: 主題 , 語言等 )

使用步驟:

1. 呼叫 React.createContext() 建立 Provider (提供資料) 和 Consumer (消費資料) 兩個元件

const { Provider , Consumer } = React.createContext()

2. 使用 Provider 元件作為父節點

<Provider>
  <div className="App">
    <Child1 />
  </div>
</Provider>

3. 設定 value 屬性 , 表示要傳遞的資料

<Provieder value="pauline_">

4. 呼叫 Consumer 元件接收資料

<Consumer>
  { data => <span> data 參數列示接受資料 -- { data } </span>
<Consumer>
const { Provider, Consumer } = React.createContext()

class App extends React.Component {
  render() {
    return (
      <Provider value="pauline_">
        <div className="App" >
          <Node />
        </div>
      </Provider>
    )
  }
}

const Node = props => {
  return (
    <div className="node">
      <SubNode />
    </div>
  )
}

const SubNode = props => {
  return (
    <div className="subnode">
      <Child />
    </div>
  )
}

const Child = props => {
  return <div className="child">
    // data表示接受資料 -- pauline_
    <Consumer>{data => <span>data表示接受資料 -- {data}</span>}</Consumer>
  </div>
}

ReactDOM.render(<App />, document.getElementById('root'))

props 深入

children 屬性

  • children 屬性 : 表示元件標籤的子節點. 當元件標籤有子節點時 , props就會有該屬性
  • children 屬性與普通 props 一樣 , 值可以是任意值( 文字 , React元素 , 元件 , 甚至是函式 )
function Hello(props) {
  console.log(props);
  return (
    <div>
      元件的子節點: {props.children}
    </div>
  )
}

ReactDOM.render(<Hello>我是子節點</Hello>, document.getElementById('root'))

props 效驗

  • 對於元件來說 , props是外來的 , 無法保證元件使用者傳入什麼格式的資料
  • 如果傳入的資料格式不對 , 可能會導致元件內部報錯
  • 關鍵問題: 元件的使用者不知道明確的錯誤原因
  1. props 效驗: 允許在建立元件的時候 , 就指定props的型別 . 格式等
  2. 作用: 捕獲使用元件時因為 props 導致的錯誤 , 給出明確的錯誤提示 , 增加元件的健壯性

App.propTypes = {
  colors : PropTypes.array
 

 使用步驟

1.安裝包

npm i props-types

2. 匯入 prop-types 包

3.  使用 元件名.propTypes = {} 來給元件的props新增效驗規則

function App(props) {
  return (
    <h1>Hi , {props.colors}</h1>
  )
}
App.propTypes = {
  // 約定colors 屬性為Array型別
  // 如果型別不對 , 則報出明顯錯誤 , 便於分析錯誤原因
  colors: PropTypes.array
}
ReactDOM.render(<App />, document.getElementById('root'))

約束規則

  1. 常見型別: array , bool , func , number , object , string 
  2. React 元素型別 : element
  3. 必填項 : isRequired
// 常見型別
element: PropTypes.func,

//必選
element: PropTypes.func.isRequired,

// 特定結構的物件
element: PropTypes.shape({
  color: PropTypes.string,
  fontSize: PropTypes.number
})

props的預設值

  • 場景: 分頁元件 => 每頁顯示條數
function App(props) {
  console.log(props);
  return (
    <div>
      此處展示props的預設值:{props.pageSize}
    </div>
  )
}
//設定預設值
App.defaultProps = {
  pageSize: 10
}
// 不傳入pageSize屬性

ReactDOM.render(<App colors={[1, 2, 3]} />, document.getElementById('root'))

 

相關文章