React API 和代码重用的演变!


React API 和代码重用的演变!

文章插图
本文将探究 React API 的演变及其背后的心智模型 。从 mixins 到 hooks,再到 RSCs,了解整个过程中的权衡 。我们将对 React 的过去、现在和未来有一个更清晰的了解,便于深入研究遗留代码库并评估其他技术如何采用不同的方法并做出不同的权衡 。
React API 简史我们从面向对象的设计模式在 JS 生态系统中流行的时候开始,可以在早期的 React API 中看到这种影响 。
MixinsReact.createClass API 是创建组件的原始方式 。在 JAVAscript 支持原生类语法之前,React 就有自己的类表示 。Mixins 是一种用于代码重用的通用 OOP 模式,下面是一个简化的例子:
function ShoppingCart() {this.items = [];}var orderMixin = {calculateTotal() {// 从 this.items 计算}// .. 其他方法}Object.assign(ShoppingCart.prototype, orderMixin)var cart = new ShoppingCart()cart.calculateTotal()JavaScript 不支持多重继承,因此 mixin 是重用共享行为和扩充类的一种方式 。那该如何在使用 createClass 创建的组件之间共享逻辑呢?Mixins 是一种常用的模式,它可以访问组件的生命周期方法,允许我们组合逻辑、状态等:
var SubscriptionMixin = {getInitialState: function() {return {comments: DataSource.getComments()};},// 当一个组件使用多个 mixin 时,React 会尝试合并多个mixin的生命周期方法,因此每个都会被调用componentDidMount: function() {console.log('do something on mount')},componentWillUnmount: function() {console.log('do something on unmount')},}// 将对象传递给 createClassvar CommentList = React.createClass({// 在 mixins 属性下定义它们mixins: [SubscriptionMixin, AnotherMixin, SomeOtherMixin],render: function() {var { comments, ...otherStuff } = this.statereturn (<div>{comments.map(function(comment) {return <Comment key={comment.id} comment={comment} />})}</div>)}})对于较小的应用,这种方式可以正常运行 。但是,当 Mixin 应用到大型项目时,它们也有一些缺点:
  • 名称冲突:Mixin 具有共享的命名空间,当多个 Mixin 使用同一个方法或状态的名称时,会发生冲突 。
  • 隐式依赖关系:确定哪个 Mixin 提供了哪些功能或状态比较麻烦 。它们使用共享的属性键相互交互,从而创建隐式耦合 。
  • 难以理解和调试:Mixin 通常使组件更难以理解和调试 。例如,上面多个 Mixin 都可以对 getInitialState 结果有影响,使得跟踪问题变得更加困难 。
在感受到这些问题的痛苦之后,React 团队发布了“Mixins Considered Harmful”,不鼓励继续使用这种模式 。
高阶组件当 Javascript 中支持了原生类语法后,React 团队就在 v15.5 中弃用了 createClass API,支持原生类 。
在这个转变过程中,我们仍然按照类和生命周期的思路来思考,因此没有进行重大的心智模型转变 。现在可以扩展包含生命周期方法的 Reacts Component 类:
class MyComponent extends React.Component {constructor(props) {// 在组件挂载到 DOM 之前运行// super 指的是父 Component 的构造函数super(props)}componentWillMount() {}componentDidMount(){}componentWillUnmount() {}componentWillUpdate() {}shouldComponentUpdate() {}componentWillReceiveProps() {}getSnapshotBeforeUpdate() {}componentDidUpdate() {}render() {}}【React API 和代码重用的演变!】考虑到 mixin 的缺陷,我们该如何以这种编写 React 组件的新方式来共享逻辑和副作用呢?
这时候,高阶组件 (HOC) 就出现了,它的名字来源于高阶函数的函数式编程概念 。它成为了替代 Mixin 的一种流行方式,并出现在像 Redux 这样的库的 API 中,例如它的 connect 函数,用于将组件连接到 Redux 存储 。除此之外,还有 React Router 的 withRouter 。
// 一个创建增强组件的函数,有一些额外的状态、行为或 propsconst EnhancedComponent = myHoc(MyComponent);// HOC 的简化示例function myHoc(Component) {return class extends React.Component {componentDidMount() {console.log('do stuff')}render() {// 使用一些注入的 props 渲染原始组件return <Component {...this.props} extraProps={42} />}}}高阶组件对于在多个组件之间共享通用行为非常有用 。它们使包装的组件保持解耦和通用性,以便可以重用 。然而,HOC 遇到了与 mixin 类似的问题: