React中render Props模式

南風晚來晚相識發表於2022-06-18

React元件複用

React元件複用的方式有兩種:
1.render Props模式
2.高階元件HOC
上面說的這兩種方式並不是新的APi。
而是利用Raect自身的編碼特點,演化而來的固定編碼寫法。

什麼是render Props模式

1.把prop是一個函式並且要告訴元件要渲染什麼內容的技術,叫做render Props模式。
2.注意的是:並不是該模式叫做render Props就必須使用名為render的props,
實際上可以使用任意的props。
對上面者一句話的詳細說明:
子元件向父元件丟擲資料的時候使用的是:
this.props.render(資料)中render可以是其他名,如果GiveFather.

render Props的簡單使用

現在我們有一個有的需求。
游標放在螢幕上,時時獲取當前座標的位置。
請封裝為一個元件。

MoveCom.js 時時獲取當前座標的位置

import React from 'react';
class MoveCom extends React.Component{
  // 提供位置資料
  state = {
    x: 0,
    y:0,
  }
  // 獲取滑鼠的當前座標
  moveHandler = e => { 
    this.setState({
        x: e.clientX,
        y:e.clientY
    })
  }
  // 監聽滑鼠的行為
  componentDidMount() { 
    // DOM已經渲染完成了;可以進行DOM操作
    window.addEventListener('mousemove',this.moveHandler)
  }
  render() { 
    // 將元件中的資料暴露出去this.props.render(資料)
    return this.props.render(this.state)
  }
}
export default MoveCom

父元件展示位置

import React from 'react';
import ReactDOM from 'react-dom'; 
import ClassCom from "./components/ClassCom"
import MoveCom from './components/MoveCom'
class Father extends React.Component{
  render() { 
    return (
      <div>
        <h2> render Props的簡單使用</h2>
        { /* 接受子元件向上丟擲來的資料*/}
        <MoveCom render={sonGiveData => {
          return (
            <p>當前滑鼠的座標橫座標: {sonGiveData.x }  縱座標: {sonGiveData.y }</p>
          )
        }}></MoveCom>
      </div>
    )
  }
}
ReactDOM.render(
  <Father></Father>,
  document.getElementById('root')
)

總結

1. 如何將子元件中的資料丟擲去
render() { 
    return this.props.render(資料) 
}

父元件接受資料
<MoveCom render={sonGiveData => {
  return (
    <!-- 渲染的html以及資料 -->
    <p>當前滑鼠的座標橫座標: {sonGiveData } </p>
  )
}}></MoveCom>

我們發現上面這個元件只實現了狀態。
並沒有實現UI結構的渲染。
UI結構的渲染是交給render函式來決定返回的內容。

小技巧:在React中 left,right,top,bottom是不需要加上px的。
<p style={{ position:'absolute', left:100, top:200 }}> 不需要加上px的 </p>

this.props.render(資料) 可以將資料傳遞出去
再次說明:上面這個render這個不一定非要叫做render。
只是這樣寫render了,你頁可以叫做Aa,接受的時候使用也用Aa接收。

其實推薦children去代替render。因為這樣更加語義化一些的。
在實際寫的過程中也是用children。
下面我們來將程式碼更改一下,children去代替render。

children去代替render語法上的變化

1.使用render子元件向上丟擲資料:
this.props.render(資料) 

1.使用children子元件向上丟擲資料:
this.props.children(資料)
在向上丟擲資料的時候,只是render變為了children。

2.render接受資料:
<MoveCom render={sonGiveData => {
    return (
        <p>當前滑鼠的座標橫座標: {sonGiveData } </p>
    )
}}></MoveCom>

2.children接收資料:
<MoveCom>
  {
    (data) => {
      return (
        <p style={{ position:'absolute', left:data.x, top:data.y }}>
          橫座標: {data.x }  縱座標: {data.y }
        </p>
      )
    }
  }
</MoveCom>
render接收資料的時候,資料是寫在元件上
children接收的時候,將資料寫在了裡面。

render Props中使用 children去代替render

子元件
import React from 'react';
class MoveCom extends React.Component{
  // 提供位置資料
  state = {
    x: 0,
    y:0,
  }
  // 獲取滑鼠的當前座標
  moveHandler = e => { 
    this.setState({
      x: e.clientX,
      y:e.clientY
    })
  }
  // 監聽滑鼠的行為
  componentDidMount() { 
    // DOM已經渲染完成了;可以進行DOM操作
    window.addEventListener('mousemove',this.moveHandler)
  }
  render() { 
    // 將子元件中的資料暴露出去,render變為了children
    return this.props.children(this.state)
  }
}
export default MoveCom

父元件
import React from 'react';
import ReactDOM from 'react-dom'; 
import ClassCom from "./components/ClassCom"
import MoveCom from './components/MoveCom'
class Father extends React.Component{
  render() { 
    return (
      <div>
        <h2> render Props的簡單使用</h2>
        <MoveCom>
          {
            (data) => {
              return (
                <p style={{ position:'absolute', left:data.x, top:data.y }}>
                    橫座標: {data.x }  縱座標: {data.y }
                </p>
              )
            }
          }
        </MoveCom>
      </div>
    )
  }
}

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

優化React中render Props模式

1.推薦給render Props新增一個校驗。
因為render Props接收的是一個函式並且是必須寫的。
// 規則校驗
MoveCom.propTypes = {
  // 如果是使用的children
  children: PropTypes.func.isRequired
  // render: PropTypes.func.isRequired 如果使用使用的render
}

2.移出事件繫結
 // 元件即將解除安裝的時候,移出事件監聽
componentWillUnmount() { 
  window.removeEventListener('mousemove',this.moveHandler)
}

3.這裡為什麼要移出事件繫結
而我們在頁面中用onClick繫結的事件不需要被移除呢?
因為onClick是借用react來完成的事件繫結,react會自動幫我們移除。
這裡我們不是借用React來完成的事件繫結,因此我們應該手動移除

子元件優化後的程式碼


import React from 'react';
import PropTypes from 'prop-types'
class MoveCom extends React.Component{
  // 提供位置資料
  state = {
    x: 0,
    y:0,
  }
  // 獲取滑鼠的當前座標
  moveHandler = e => { 
    this.setState({
      x: e.clientX,
      y:e.clientY
    })
  }
  // 監聽滑鼠的行為
  componentDidMount() { 
    // DOM已經渲染完成了;可以進行DOM操作
    window.addEventListener('mousemove',this.moveHandler)
  }

  // 元件即將解除安裝的時候,移出事件監聽-優化的地方
  componentWillUnmount() { 
    window.removeEventListener('mousemove',this.moveHandler)
  }
  render() { 
    // 將子元件中的資料暴露出去,render變為了children
    return this.props.children(this.state)
  }
}

// 規則校驗-優化的地方
MoveCom.propTypes = {
  // 如果是使用的children
  children: PropTypes.func.isRequired
  //  render: PropTypes.func.isRequired 如果使用使用的render
}

export default MoveCom

相關文章