React高階組件--render props叛复、高階組件(React學(xué)習(xí)筆記_06)

React - render props和高階組件

1怀偷,render props模式

使用步驟

  • 1家厌,創(chuàng)建一個(gè)組件,在組件中提供復(fù)用的狀態(tài)邏輯代碼
  • 2椎工,將要復(fù)用的狀態(tài)作為props.render(state)方法的參數(shù)饭于,暴露到組件外部
  • 3,使用props.render()的返回值作為要渲染的內(nèi)容
class 組件名 extends React.Component {
  state = {}
  render() {
    return this.props.render(this.state)
  }
}

<組件名 render={i => {
  return (
    <div>{i.xx}</div>
  )
}}/>

示例:

class Mouse extends React.Component {
  state = {
    x: 0,
    y: 0
  }

  handleMouseMove = e => {
    this.setState({
      x: e.clientX,
      y: e.clientY
    })
  }
  // 監(jiān)聽鼠標(biāo)移動(dòng)事件
  componentDidMount() {
    window.addEventListener('mousemove', this.handleMouseMove)
  }
  render() {
    return this.props.render(this.state)
  }
}
class App extends React.Component {
  render() {
    return (
      <div>
        <h1>哈哈哈哈</h1>
        <Mouse render={i => {
          return (
            <div>鼠標(biāo)位置:{i.x}, {i.y}</div>
          )
        }}/>

        <Mouse render={i => {
          return (
            <img src={img} style={{position: 'absolute', top: i.y - 100, left: i.x - 100}}></img>
          )
        }}/>
      </div>
    )
  }
}

children代替render屬性

  • 并不是該模式叫render props就必須使用名為render的prop维蒙,實(shí)際上可以使用任意名稱的prop
  • 把prop是一個(gè)函數(shù)并且告訴組件要渲染什么內(nèi)容的技術(shù)叫做:render props模式
  • 推薦使用children代替render屬性
class Mouse extends React.Component {
  state = {
    x: 0,
    y: 0
  }

  handleMouseMove = e => {
    this.setState({
      x: e.clientX,
      y: e.clientY
    })
  }
  // 監(jiān)聽鼠標(biāo)移動(dòng)事件
  componentDidMount() {
    window.addEventListener('mousemove', this.handleMouseMove)
  }

  // 代碼優(yōu)化項(xiàng) 2 
  // 在卸載的時(shí)候解除mousemove事件綁定
  componentWillUnmount() {
    window.removeEventListener('mousemove', this.handleMouseMove)
  }
  render() {
    // return this.props.render(this.state)
    // children代替render 
    return this.props.children(this.state)
  }
}

// 代碼優(yōu)化項(xiàng) 1
Mouse.prototypes = {
  children: PropTypes.func.isRequired,
}
class App extends React.Component {
  render() {
    return (
      <div>
        <h1>哈哈哈哈</h1>
        {/* <Mouse render={i => {
          return (
            <div>鼠標(biāo)位置:{i.x}, {i.y}</div>
          )
        }}/> */}

        {/* children代替render */}
        <Mouse>
          {
            ({x, y}) => {
              return (
                <div>鼠標(biāo)位置:{x}, {y}</div>
              )
            }
          }
        </Mouse>

        {/* <Mouse render={i => {
          return (
            <img src={img} style={{position: 'absolute', top: i.y - 100, left: i.x - 100}}></img>
          )
        }}/> */}

        {/* children代替render  */}
        <Mouse>
          {
            ({x, y}) => {
              return (
                <img src={img} style={{position: 'absolute', top: y - 100, left: x - 100}}></img>
              )
            }
          }
        </Mouse>
      </div>
    )
  }
}

2, 高階組件(HOC)

目的是實(shí)現(xiàn)狀態(tài)邏輯復(fù)用镰绎。

使用步驟:

  • 1,創(chuàng)建一個(gè)函數(shù)木西,名稱約定以with開頭
  • 2,指定函數(shù)參數(shù)随静,參數(shù)應(yīng)該以大寫字母開頭(作為要渲染的組件)
  • 3八千,在函數(shù)內(nèi)部創(chuàng)建一個(gè)類組件,提供復(fù)用的狀態(tài)邏輯代碼燎猛,并返回
  • 4恋捆,在該組件中,渲染參數(shù)組件重绷,同時(shí)將狀態(tài)通過(guò)prop傳遞給參數(shù)組件
  • 5沸停,調(diào)用該高階組件,傳入要增強(qiáng)的組件昭卓,通過(guò)返回值拿到增強(qiáng)后的組件愤钾,并將其渲染到頁(yè)面中
function withMouse(WrappendComponent) {
  class Mouse extends React.Component{
    return Mouse
  }
}

// Mouse組件的render方法中:
return <WrappendComponent {...this.state}/>

// 創(chuàng)建組件
const MousePosition = widthMouse(Position)

// 渲染組件
<MousePosition />

以上示例改為高階組件:

// 創(chuàng)建高階組件
function widthMouse(WrappedComponent) {
  // 該組件提供復(fù)用的狀態(tài)邏輯
  class Mouse extends React.Component {
    state = {
      x: 0,
      y: 0
    }

    handleMouseMove = e => {
      this.setState({
        x: e.clientX,
        y: e.clientY
      })
    }
    componentDidMount() {
      window.addEventListener('mousemove', this.handleMouseMove)
    }

    componentWillUnmount() {
      window.removeEventListener('mousemove', this.handleMouseMove)
    }

    render() {
      return <WrappedComponent {...this.state}/>
    }
  }

  return Mouse
}

// 用來(lái)測(cè)試高階組件 獲取鼠標(biāo)移動(dòng)的位置的組件
const Position = props => (
  <p>
    鼠標(biāo)當(dāng)前位置: (x: {props.x}, y: {props.y})
  </p>
)

// 用來(lái)測(cè)試獲取圖片跟隨鼠標(biāo)動(dòng)的組件
const ImgPosition = props => (
  <img src={img} style={{
    position: 'absolute',
    top: props.y - 100,
    left: props.x - 100
  }}></img>
)

// 獲取增強(qiáng)后的組件
const MousePosition = widthMouse(Position)

const MouseImg = widthMouse(ImgPosition)

class App extends React.Component {
  render() {
    return (
      <div>
        <h1>高階組件</h1>
        <MousePosition/>
        <MouseImg/>
      </div>
    )
  }
}
設(shè)置displayName
  • 使用高階組件存在的問(wèn)題:得到的兩個(gè)組件名稱相同
  • 原因:默認(rèn)情況下,React使用組件名稱作為displayName
  • 解決方式: 為高階組件設(shè)置displayName便于調(diào)試的時(shí)候區(qū)分不同的組件
  • displayName的作用:用于設(shè)置調(diào)試信息(React developer tools)
  • 設(shè)置方式
Mouse.displayName = `widthMouse${getDisplayName(WrappedComponent)}`

function getDisplayName(WrappedComponent) {
  return WrappedComponent.displayName || WrappedComponent.name || 'xiaowang'
}

以上示例改寫為設(shè)置displayName

function widthMouse(WrappedComponent) {
  // 該組件提供復(fù)用的狀態(tài)邏輯
  class Mouse extends React.Component {
    state = {
      x: 0,
      y: 0
    }

    handleMouseMove = e => {
      this.setState({
        x: e.clientX,
        y: e.clientY
      })
    }
    componentDidMount() {
      window.addEventListener('mousemove', this.handleMouseMove)
    }

    componentWillUnmount() {
      window.removeEventListener('mousemove', this.handleMouseMove)
    }

    render() {
      return <WrappedComponent {...this.state}/>
    }
  }
  // 設(shè)置displayName
  Mouse.displayName = `widthMouse${getDisplayName(WrappedComponent)}`  // widthMousePosition widthMouseImgPosition

  return Mouse
}

function getDisplayName(WrappedComponent) {
  console.log('WrappedComponent=====>', WrappedComponent.displayName)  // undefined undefined
  console.log('WrappedComponent=====>', WrappedComponent.name)  // Position ImgPosition
  return WrappedComponent.displayName || WrappedComponent.name || 'xiaoWangComponent'
}

// 用來(lái)測(cè)試高階組件 獲取鼠標(biāo)移動(dòng)的位置的組件
const Position = props => (
  <p>
    鼠標(biāo)當(dāng)前位置: (x: {props.x}, y: {props.y})
  </p>
)

// 用來(lái)測(cè)試獲取圖片跟隨鼠標(biāo)動(dòng)的組件
const ImgPosition = props => (
  <img src={img} style={{
    position: 'absolute',
    top: props.y - 100,
    left: props.x - 100
  }}></img>
)

// 獲取增強(qiáng)后的組件
const MousePosition = widthMouse(Position)

const MouseImg = widthMouse(ImgPosition)

class App extends React.Component {
  render() {
    return (
      <div>
        <h1>高階組件</h1>
        <MousePosition/>
        <MouseImg/>
      </div>
    )
  }
}
高階組件 傳遞props
  • props丟失
  • 原因:高階組件沒(méi)有往下傳遞props
  • 解決方式:渲染W(wǎng)rappedComponent時(shí)候醒,將state和this.props一起傳遞給組件
  • 傳遞方式
<WrappedComponent {...this.state} {...this.props}></WrappedComponent>

以上示例涉及到修改的代碼:

function widthMouse(WrappedComponent) {
  // 該組件提供復(fù)用的狀態(tài)邏輯
  // class Mouse extends React.Component {
  //   state = {
  //     x: 0,
  //     y: 0
  //   }

    // handleMouseMove = e => {
    //   this.setState({
    //     x: e.clientX,
    //     y: e.clientY
    //   })
    // }
    // componentDidMount() {
    //   window.addEventListener('mousemove', this.handleMouseMove)
    // }

    // componentWillUnmount() {
    //   window.removeEventListener('mousemove', this.handleMouseMove)
    // }

    render() {
      // Mouse組件中可以拿到other這個(gè)屬性
      console.log('this.props=====>', this.props)
      return <WrappedComponent {...this.state} {...this.props}/>
    }
  }
  // 設(shè)置displayName
  // Mouse.displayName = `widthMouse${getDisplayName(WrappedComponent)}`  // widthMousePosition widthMouseImgPosition

  return Mouse
}

// function getDisplayName(WrappedComponent) {
//   console.log('WrappedComponent=====>', WrappedComponent.displayName)  // undefined undefined
//   console.log('WrappedComponent=====>', WrappedComponent.name)  // Position ImgPosition
//   return WrappedComponent.displayName || WrappedComponent.name || 'xiaoWangComponent'
// }

// 用來(lái)測(cè)試高階組件 獲取鼠標(biāo)移動(dòng)的位置的組件
const Position = props => {
  // position組件沒(méi)有拿到other屬性
  console.log('position組件:=====>', props)
  return (
    <p>
      鼠標(biāo)當(dāng)前位置: (x: {props.x}, y: {props.y})
    </p>
  )
}

// 用來(lái)測(cè)試獲取圖片跟隨鼠標(biāo)動(dòng)的組件
// const ImgPosition = props => (
//   <img src={img} style={{
//     position: 'absolute',
//     top: props.y - 100,
//     left: props.x - 100
//   }}></img>
// )

// 獲取增強(qiáng)后的組件
// const MousePosition = widthMouse(Position)

// const MouseImg = widthMouse(ImgPosition)

class App extends React.Component {
  render() {
    return (
      <div>
        {/* <h1>高階組件</h1> */}
        <MousePosition other="哈哈哈"/>
        {/* <MouseImg/> */}
      </div>
    )
  }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末能颁,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子倒淫,更是在濱河造成了極大的恐慌伙菊,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,000評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異镜硕,居然都是意外死亡运翼,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門兴枯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)血淌,“玉大人,你說(shuō)我怎么就攤上這事念恍×” “怎么了?”我有些...
    開封第一講書人閱讀 168,561評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵峰伙,是天一觀的道長(zhǎng)疗疟。 經(jīng)常有香客問(wèn)我,道長(zhǎng)瞳氓,這世上最難降的妖魔是什么策彤? 我笑而不...
    開封第一講書人閱讀 59,782評(píng)論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮匣摘,結(jié)果婚禮上店诗,老公的妹妹穿的比我還像新娘。我一直安慰自己音榜,他們只是感情好庞瘸,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,798評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著赠叼,像睡著了一般擦囊。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上嘴办,一...
    開封第一講書人閱讀 52,394評(píng)論 1 310
  • 那天瞬场,我揣著相機(jī)與錄音,去河邊找鬼涧郊。 笑死贯被,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的妆艘。 我是一名探鬼主播彤灶,決...
    沈念sama閱讀 40,952評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼双仍!你這毒婦竟也來(lái)了枢希?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,852評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤朱沃,失蹤者是張志新(化名)和其女友劉穎苞轿,沒(méi)想到半個(gè)月后茅诱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,409評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡搬卒,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,483評(píng)論 3 341
  • 正文 我和宋清朗相戀三年瑟俭,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片契邀。...
    茶點(diǎn)故事閱讀 40,615評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡摆寄,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出坯门,到底是詐尸還是另有隱情微饥,我是刑警寧澤,帶...
    沈念sama閱讀 36,303評(píng)論 5 350
  • 正文 年R本政府宣布古戴,位于F島的核電站欠橘,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏现恼。R本人自食惡果不足惜肃续,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,979評(píng)論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望叉袍。 院中可真熱鬧始锚,春花似錦、人聲如沸喳逛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)润文。三九已至察郁,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間转唉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工稳捆, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留赠法,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,041評(píng)論 3 377
  • 正文 我出身青樓乔夯,卻偏偏與公主長(zhǎng)得像砖织,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子末荐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,630評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容