render-props模式
將可以復(fù)用的state和操作state的方法封裝到一個(gè)獨(dú)立的組件中,可以提高開(kāi)發(fā)效率
props.render()模式
demo: 定義一個(gè)獲取鼠標(biāo)位置的組件
創(chuàng)建Mouse組件,在組件中提供復(fù)用的代碼邏輯
-
將狀態(tài)作為
props.render(state)
方法的參數(shù),暴露到組件外部注意: 不一定要叫
render
也可以使用其他名稱,復(fù)用時(shí)與之一致即可
import { Component } from 'react'
export default class Mouse extends Component {
state = {
x: 0,
y: 0
}
// 監(jiān)聽(tīng)鼠標(biāo)移動(dòng)事件
componentDidMount() {
window.addEventListener('mousemove', this.handleMouseMove)
}
// 組件限載時(shí)解綁事件
componentWillUnmount() {
window.removeEventListener('mousemove', this.handleMouseMove)
}
handleMouseMove = e => {
this.setState({
x: e.clientX,
y: e.clientY
})
}
render() {
// 向外界提供當(dāng)前子組件里面的數(shù)據(jù) render模式
// show是自定義的名稱,復(fù)用時(shí)與之對(duì)應(yīng)即可
return this.props.show(this.state)
}
}
定義一個(gè)Position
類式組件
import React, { Component } from 'react'
export default class Position extends Component {
render() {
return (
<div>
<h2>鼠標(biāo)當(dāng)前x坐標(biāo)軸: {this.props.x}</h2>
<h2>鼠標(biāo)當(dāng)前y坐標(biāo)軸: {this.props.y}</h2>
</div>
)
}
}
將Mouse
組件和Position
組件引入到App組件中
將Mouse
組件暴露的方法作為Mouse
標(biāo)簽屬性,綁定一個(gè)回調(diào)函數(shù),回調(diào)函數(shù)的形參就是暴露出來(lái)的數(shù)據(jù)
將數(shù)據(jù)傳入需要復(fù)用的組件內(nèi)部
import React, { Component } from 'react'
import Mouse from './Mouse'
import Position from './components/Position'
export default class App extends Component {
render() {
return (
<div>
{/* render 模式 復(fù)用 類式組件 */}
<Mouse show={(mouse) => <Position {...mouse}></Position>}>
</Mouse>
</div>
)
}
}
定義一個(gè)Picture
函數(shù)式組件,實(shí)現(xiàn)鼠標(biāo)跟隨效果
import React from 'react'
import pic from '../static/1.gif'
export default function Picture(props) {
return (
<div>
<img
src={pic}
alt=""
style={{ position: 'absolute', left: props.x - 100 + 'px', top: props.y - 50 + 'px', width: '200px', height: '200px' }}
/>
</div>
)
}
在App組件中引入Picture
組件
函數(shù)式組件在使用的時(shí)候,不需要以標(biāo)簽的形式渲染,而是使用函數(shù)的形式,
數(shù)據(jù)直接通過(guò)函數(shù)的參數(shù)傳入組件內(nèi)部
import React, { Component } from 'react'
import Mouse from './Mouse'
import Position from './components/Position'
import Picture from './components/Picture'
export default class App extends Component {
render() {
return (
<div>
{/* render 模式 復(fù)用 類式組件 */}
<Mouse show={(mouse) => <Position {...mouse}></Position>}>
</Mouse>
{/* render 模式 復(fù)用 函數(shù)式組件 */}
<Mouse show={mouse => Picture(mouse)}></Mouse>
</div>
)
}
}
使用children代替render
使用props.children()
暴露狀態(tài),在復(fù)用組件的時(shí)候,可以將組件當(dāng)成子組件使用
推薦使用children代替render
demo:修改Mouse
組件暴露狀態(tài)的方式
import { Component } from 'react'
export default class Mouse extends Component {
state = {
x: 0,
y: 0
}
// 監(jiān)聽(tīng)鼠標(biāo)移動(dòng)事件
componentDidMount() {
window.addEventListener('mousemove', this.handleMouseMove)
}
// 組件限載時(shí)解綁事件
componentWillUnmount() {
window.removeEventListener('mousemove', this.handleMouseMove)
}
handleMouseMove = e => {
this.setState({
x: e.clientX,
y: e.clientY
})
}
render() {
// 向外界提供當(dāng)前子組件里面的數(shù)據(jù) children模式
return this.props.children(this.state)
}
}
將定義的類式組件和函數(shù)式組件引入到App組件
import React, { Component } from 'react'
import Mouse from './Mouse'
import Position from './components/Position'
import Picture from './components/Picture'
export default class App extends Component {
render() {
return (
<div>
{/* children 模式 復(fù)用 類式組件 */}
<Mouse>
{
mouse => <Position {...mouse}></Position>
}
</Mouse>
{/* children 模式 復(fù)用 函數(shù)式組件 */}
<Mouse>
{
mouse => Picture(mouse)
}
</Mouse>
</div>
)
}
}
高階組件
采用包裝模式來(lái)實(shí)現(xiàn)狀態(tài)的復(fù)用,通過(guò)包裝組件,來(lái)增強(qiáng)組件的功能
使用步驟
- 在可復(fù)用組件內(nèi)創(chuàng)建一個(gè)函數(shù),函數(shù)名以
with
開(kāi)頭 - 指定函數(shù)的參數(shù),參數(shù)名稱以大寫(xiě)字母開(kāi)頭(調(diào)用函數(shù)時(shí)傳入的是組件名稱)
- 在函數(shù)創(chuàng)建一個(gè)類式組件,提供復(fù)用狀態(tài)的邏輯代碼,并返回
- 在組件的
render()
方法里返回以函數(shù)參數(shù)為名稱的標(biāo)簽,并將狀態(tài)傳入組件 - 引入高階組件,傳入需要增強(qiáng)的組件,并暴露出來(lái)
demo
定義一個(gè)高階組件
import { Component } from 'react'
// 定義一個(gè)函數(shù),在函數(shù)內(nèi)部創(chuàng)建一個(gè)類式組件
// 傳遞的參數(shù)是一個(gè)組件,所以形參的首字母需要大寫(xiě)
const withMouse = WarppedComponent => {
class Mouse extends Component {
state = {
x: 0,
y: 0
}
// 監(jiān)聽(tīng)鼠標(biāo)移動(dòng)事件
componentDidMount() {
window.addEventListener('mousemove', this.handleMouseMove)
}
// 組件限載時(shí)解綁事件
componentWillUnmount() {
window.removeEventListener('mousemove', this.handleMouseMove)
}
// 事件的處理函數(shù)
handleMouseMove = e => {
this.setState({
x: e.clientX,
y: e.clientY
})
}
render() {
// 返回傳遞過(guò)來(lái)的組件思劳,把當(dāng)前組件的狀態(tài)設(shè)置進(jìn)去
return <WarppedComponent {...this.state} />
}
}
return Mouse
}
export default withMouse
在組件內(nèi)使用高階組件
引入高階組件,將需要增強(qiáng)的組件傳入高階組件
import React, { Component } from 'react'
import withMouse from '../withMouse'
class Position extends Component {
render() {
return (
<div>
<h2>鼠標(biāo)當(dāng)前x坐標(biāo)軸: {this.props.x}</h2>
<h2>鼠標(biāo)當(dāng)前y坐標(biāo)軸: {this.props.y}</h2>
</div>
)
}
}
export default withMouse(Position)
在App組件內(nèi)使用的方法和一般情況一致
import React, { Component } from 'react'
import Position from './components/Position'
import Picture from './components/Picture'
export default class App extends Component {
render() {
return (
<div>
<Position />
<Picture />
</div>
)
}
}
使用displayName
使用了高階組件之后會(huì)存在一個(gè)問(wèn)題: 開(kāi)發(fā)者工具會(huì)顯示兩個(gè)組件名稱一樣的組件
因?yàn)槟J(rèn)情況下, React會(huì)使用組件名稱作為組件名稱,所有在兩個(gè)組件都使用了高階組件的情況下,兩個(gè)組件的外殼都是其高階組件的名稱
解決方案: 手動(dòng)設(shè)置displayName
使用步驟
-
在高階組件的函數(shù)內(nèi)部定義一個(gè)函數(shù)
getDisplayName(){}
把傳入組件作為參數(shù)傳入這個(gè)函數(shù)
效果圖: 使用前import { Component } from 'react' // 定義一個(gè)函數(shù),在函數(shù)內(nèi)部創(chuàng)建一個(gè)類式組件 const withMouse = WarppedComponent => { class Mouse extends Component { // 復(fù)用的邏輯代碼 } // 設(shè)置開(kāi)發(fā)者工具顯示名稱,如果不設(shè)置開(kāi)發(fā)者工具顯示的外殼組件都是一樣的 function getDisplayName(WarppedComponent) { return WarppedComponent.displayName || WarppedComponent.name || 'Component' } // 給組件添加displayName屬性 Mouse.displayName = `WithMouse${getDisplayName(WarppedComponent)}` return Mouse } export default withMouse
使用后