寫過react項目的應該都碰到過,不一樣組件複用相同代碼的問題,在react早期使用React.createClass建立組件的時代,咱們常用的是mixins來實現代碼複用。好比有個組件A,它用來實時的獲取鼠標的位置。react
//A組件
import React from 'react'
import ReactDOM from 'react-dom'
const App = React.createClass({
getInitialState() {
return { x: 0, y: 0 }
},
handleMouseMove(event) {
this.setState({
x: event.clientX,
y: event.clientY
})
},
render() {
const { x, y } = this.state
return (
<div style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>
<h1>The mouse position is ({x}, {y})</h1>
</div>
)
}
})
ReactDOM.render(<App/>, document.getElementById('app'))
複製代碼
若是此時有個組件B也想集成這個功能,咱們能夠經過mixins,代碼是這樣的git
//B組件
import React from 'react'
import ReactDOM from 'react-dom'
const MouseMixin = {
getInitialState() {
return { x: 0, y: 0 }
},
handleMouseMove(event) {
this.setState({
x: event.clientX,
y: event.clientY
})
}
}
const App = React.createClass({
// Use the mixin!
mixins: [ MouseMixin ],
render() {
const { x, y } = this.state
return (
<div style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>
<h1>The mouse position is ({x}, {y})</h1>
</div>
)
}
})
ReactDOM.render(<App/>, document.getElementById('app'))
複製代碼
很容易是吧~但委屈的是react16以後就再也不支持mixins了,由於es6普及了呀!。es6
因此爲了代替mixins,不少人就提出了HOC(高階組件),代碼是下面這樣的。github
import React from 'react'
import ReactDOM from 'react-dom'
const withMouse = (Component) => {
return class extends React.Component {
state = { x: 0, y: 0 }
handleMouseMove = (event) => {
this.setState({
x: event.clientX,
y: event.clientY
})
}
render() {
return (
<div style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>
<Component {...this.props} mouse={this.state}/>
</div>
)
}
}
}
class App extends React.Component{
render() {
// 代替直接處理state,咱們從props裏得到x,y座標
const { x, y } = this.props.mouse
return (
<div style={{ height: '100%' }}>
<h1>The mouse position is ({x}, {y})</h1>
</div>
)
}
}
//把App組件當作參數傳到withMouse方法裏面,在withMouse內部經過props得到x、y座標值
const AppWithMouse = withMouse(App)
ReactDOM.render(<AppWithMouse/>, document.getElementById('app'))
複製代碼
看起來很不錯的樣子!bash
個人天.....react-router
幸運女神降臨! mmp,前面都是炮灰,到了劃重點的時候啦!
app
Render Prop是個值爲函數的屬性,經過Render Prop,組件知道什麼應該被渲染dom
很糊塗是否是,看代碼函數
import React from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'
class Mouse extends React.Component {
static propTypes = {
render: PropTypes.func.isRequired
}
state = { x: 0, y: 0 }
handleMouseMove = (event) => {
this.setState({
x: event.clientX,
y: event.clientY
})
}
render() {
return (
<div style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>
{this.props.render(this.state)}
</div>
)
}
}
const App = React.createClass({
render() {
return (
<div style={{ height: '100%' }}>
<Mouse render={({ x, y }) => (
<h1>The mouse position is ({x}, {y})</h1>
)}/>
</div>
)
}
})
ReactDOM.render(<App/>, document.getElementById('app'))
複製代碼
看明白了麼,這裏咱們經過定義一個render屬性,值是個函數,描述了咱們想要渲染的元素,而後在子組件裏面調用該render方法,再回頭看下以前的兩個問題,難以溯源,如今主動權在父組件上,我要什麼數據大家給我拿來就好了,大家子組件各自去實現,我只要結果不要過程,於是就不存在數據來源問題,命名空間的問題也沒了。好厲害~~~。 最後偷偷的告訴大家一個更厲害的,上面的render方法裏面咱們是直接寫出了渲染x,y值,只適用於當前App組件,咱們能夠經過高階組件來達到爲任何組件添加該功能,代碼是這樣的。學習
const withMouse = (Component) => {
return class extends React.Component{
render() {
return <Mouse render={mouse=>(
<Component {...this.props} mouse={mouse}/>
)}/>
}
}
}
複製代碼
聽說react-router源碼裏面爲每一個組件增長路由屬性就是經過該方法!
好了!大功完成了,歡迎一塊兒討論學習~
我的博客地址:意卿