当您将组件传递给函数并返回一个新组件时,它称为 高阶组件 (HOC)。 如果这听起来很简单,那就是! 而且您的代码使用起来会更简单。
在这篇文章的过程中,您将看到高阶组件抽象如何使您的工作更具可读性、可重用性和可组合性。
一些条款
在我们继续之前,让我们定义我们正在创建的高阶版本是什么。 虽然您可能会看到这些定义可以互换使用,但重要的是要了解它们的区别:
- Node:已挂载在 DOM 上的 HTML 元素。 您的浏览器正在渲染它,JavaScript 可以操纵它。
- Instance:组件类的运行时实例。 这些在内存中表示为 JavaScript 对象。
- Element:描述节点或可能实例的标记位。 在 React 中,这些被转译为 JavaScript 对象,这些对象又在运行时成为实例。
- Component:对元素的抽象。 它们可能带有一些内部状态,并且根据接收到的道具,它们的行为可能会有所不同。 当被要求渲染时,组件返回元素。
- 高阶组件(HOC):对组件的抽象。 当给定一个组件(可能还有一些其他参数)时,它们会返回一个新组件。
潜水
假设我们即将开始在我们的应用程序的用户页面上工作。 我们知道我们的 User 对象是什么样的,但是我们还没有完全决定我们想要使用什么样的授权。 当我们确定正确的方向时,我们如何才能避免以后的一些心痛? 当页面已经完成时,我们如何预期在三个月内改变主意的可能性?
我们可以从一个名为 withUser
的简单 HOC 函数开始。 我们希望这个函数包裹我们传递给它的任何组件,并提供我们的 User 对象作为道具。
const withUser = WrappedComponent => { class WithUser extends React.Component { constructor(props) { super(props); this.state = { user: sessionStorage.getItem("user") }; } render() { return <^>{...this.props} />; } } return WithUser; };<^>
解释:
- 我们的函数
withUser
将任何组件作为参数。 - 在内部,我们创建了一个
WithUser
组件类,它从sessionStorage
读取用户对象并将其添加到状态中。 - render 函数将
WrappedComponent
作为新元素返回,并带有来自 state 的用户属性。 - 我们将外部
this.props
传递给内部WrappedComponent
。
或者,如果不需要状态,建议使用函数式 HOC:
const withUser = WrappedComponent => { const user = sessionStorage.getItem("user"); return props => ; };
使用 HOC
当我们想要访问页面上的 User 对象时,我们可以调用 withUser
来包装页面的组件:
const UserPage = props => ( <div class="user-container"> <p>My name is {props.user}!</p> </div> ); export default withUser(UserPage);
就这样! 我们的 withUser
函数将一个组件作为参数并返回一个高阶组件。 从现在开始的三个月后,如果我们决定改变一些事情,我们只需要编辑我们的 HOC。
在野外
如果您以前不熟悉 HOC,那么您可能会在不知不觉中遇到它们! 一些值得注意的例子:
- react-redux:
connect(mapStateToProps, mapDispatchToProps)(UserPage)
- 反应路由器:
withRouter(UserPage)
- 材质-ui:
withStyles(styles)(UserPage)
奖金
redux 中的 compose
函数允许将多个 HOC 组合为一个。 例如:
import { compose } from 'redux'; // ... other imports export default compose( withStyles(styles), withRouter, withUser )(UserPage);
在这种情况下,我们的样式、路由器和用户都将传递给我们的 UserPage
组件。