掌握這個有用的模式,中止在React Components
中重複邏輯! 😎原文:React Higher Order Components in 3 minutes
做者:Jhey Tompkins
譯者:博軒javascript
高階組件(HOC)是 React
中用於複用組件邏輯的一種高級技巧。HOC
自身不是 React API
的一部分,它是一種基於 React
的組合特性而造成的設計模式。html
譯註:對,我又一次借鑑了官網 😂
他們接收一個組件並返回一個新的組件!java
當你的組件之間出現重複的模式 / 邏輯的時候。react
栗子:設計模式
UI
增長交互(也可使用容器組件,或者 Render Props)譯註:第三個說法,我我的可能更加傾向於在傳入組件以前作處理,而不是使用高階組件
咱們有一個 Mouse
組件。app
const Mouse = () => (
<span className="mouse" role="img">🐭</span>
)複製代碼
接下來,讓咱們使用 GreenSock’s Draggable 模塊,來讓組件變的能夠拖拽。函數
class Mouse extends Component {
componentDidMount = () => new Draggable(this.ELEMENT)
render = () => (
<span className="mouse" ref={e => (this.ELEMENT = e)} role="img">🐭</span>
)
}複製代碼
咱們加一隻貓 🐱ui
const Cat = () => (
<span className="cat" role="img">🐱</span>
)複製代碼
這個組件一樣須要變得可拖拽✋,接下來,讓咱們使用高階組件(HOC)來試一下:this
const withDrag = Wrapped => {
class WithDrag extends Component {
componentDidMount = () => new Draggable(this.ELEMENT)
render = () => {
return (
<span className="draggable_wrapper" ref={e => (this.ELEMENT = e)}>
<Wrapped {...this.props} />
</span>
)
}
}
WithDrag.displayName = `WithDrag(${Wrapped.displayName || Wrapped.name})`
return WithDrag;
}複製代碼
咱們的高階組件(HOC)能夠經過 props
接受一組件,並返回一個新的組件。spa
許多高階組件會在傳遞組件的過程當中,注入新的 props
。這一般是決定咱們是否應該使用高階組件的因素之一。若是,咱們不注入 props
,咱們可使用一個容器組件,或者 Render Props。
對於咱們的高階組件(HOC),咱們也可使用 Render Props 來達到相同的效果。你可能會以爲使用 HOC
來實現並不合適。可是,這個 「愚蠢的例子」 會讓你更加熟悉 HOC
。 這比注入數據的示例更加有趣!😉
讓咱們將這個 HOC
應用到 Cat
和 Mouse
組件上吧 👍
const Mouse = () => (
<span className="mouse" role="img">🐭</span>
)
const Cat = () => (
<span className="cat" role="img">🐱</span>
)
const DraggableMouse = withDrag(Mouse)
const DraggableCat = withDrag(Cat)
class App extends Component {
render = () => (
<Fragment> <DraggableMouse /> <DraggableCat /> </Fragment>
)
}複製代碼
接下來,讓咱們在高階組件中增長 onDrag
回調函數,並在 props
中注入 x
和 y
的位置屬性。
const withDrag = Wrapped => {
class WithDrag extends Component {
state = {
x: undefined,
y: undefined,
}
componentDidMount = () => new Draggable(this.ELEMENT, { onDrag: this.onDrag })
onDrag = e => {
const { x, y } = e.target.getBoundingClientRect();
this.setState({ x: Math.floor(x), y: Math.floor(y) })
}
render = () => (
<span className="draggable_wrapper" ref={e => (this.ELEMENT = e)}> <Wrapped {...this.props} x={this.state.x} y={this.state.y} /> </span> ) } WithDrag.displayName = `WithDrag(${Wrapped.displayName || Wrapped.name})` return WithDrag; }複製代碼
const Mouse = () => (
<span className="mouse" role="img">
🐭
{x !== undefined &&
y !== undefined && (
<span className="mouse__position"> {`(${x}, ${y})`} </span>
)}
</span>
)複製代碼
如今 Mouse
組件會向用戶展現他的 XY
位置屬性 🤓
咱們也能夠給 HOC
傳遞 props
。而後在傳遞的過程當中過濾掉這些無用的屬性。舉個例子,傳遞一個 onDrag
回調函數。
const withDrag = Wrapped => {
class WithDrag extends Component {
componentDidMount = () => new Draggable(this.ELEMENT, { onDrag: this.props.onDrag })
render = () => {
const { onDrag, ...passed } = this.props;
return (
<span className="draggable__wrapper" ref={e => (this.ELEMENT = e)}>
<Wrapped {...passed} />
</span>
)
}
}
WithDrag.displayName = `WithDrag(${Wrapped.displayName || Wrapped.name})`
return WithDrag;
}
class App extends Component {
render = () => (
<Fragment>
<DraggableMouse
onDrag={e => console.info(e.target.getBoundingClientRect())}
/>
</Fragment>
)
}複製代碼
經過使用 HOC
,咱們的組件仍然很簡單,複雜的邏輯都交給 HOC
來處理了。 咱們的組件只關心傳遞給他們的內容。 咱們能夠在其餘地方重複使用它們並且不會有能夠被拖拽的屬性。這使得咱們的應用更容易維護。
displayName
HOC
無關的全部 props
render
方法中使用高階組件譯註:永遠不要在React render()
方法中定義React
組件(甚至是無狀態組件)。React
在每次更新狀態的時候,都會廢棄舊的html DOM
元素並將其替換爲全新的元素。好比在render()
函數中定義一個輸入組件,元素被替換以後就會失去焦點,每次只能輸入一個字符。
Refs
不會被傳遞HOC
均可以和 render props
相互替換使用這就是一篇關於高階組件的簡短介紹 ~
withDrag Mouse and Cat (HOC)示例連接
Drag Mouse and Cat (Render Props)示例連接
withDrag Mouse and Cat (X , Y) (HOC)示例連接
Drag Mouse and Cat (X , Y)(Render Props)示例連接
Drag Mouse and Cat (X , Y)(Hooks)示例連接
官方文檔: 高階組件本文已經聯繫原文做者,並受權翻譯,轉載請保留原文連接