掌握这个有用的模式,中止在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)示例连接
官方文档: 高阶组件本文已经联系原文做者,并受权翻译,转载请保留原文连接