重新认识React组件

前言

之前分享了一篇关于如何学习React的文章,趁手还热乎,分享关于React中的组件化,来串一串零零碎碎的知识点。

开始之前,聊一下关于VueReactMVVM框架都有的特性,就是:

  • 声明式:用声明式的方式代替命令式编写UI,无需关注复杂的DOM层
  • 数据驱动:通过数据驱动自动更新和渲染组件,从而自动更新页面UI
  • 组件化:能够管理自身状态的组件,并通过合适的方式组装成复杂的UI

声明式的特性能够让开发者解放双手不去处理复杂的DOM层操作,而将注意力转移到更为重要的逻辑层,VueReact会将声明式的代码转换为命令式的DOM操作,并且利用各自高效的算法进行按需更新。

数据驱动是让页面活起来的关键,为了能够更加高效响应数据的变化并以最快的速度更新到视图,VueReact各自采用了不通的策略来处理数据。

而组件化能够将企业级大型应用通过分治思想,切割为一个个小模块(组件)进行管理,各自组件只需维护好自身状态的同时进行自由组合,开发者只需要通过【搭积木】的方式合理拼装组件,最终呈现完整的页面给用户。

了解这些对于学习React组件有什么关联呢?别急,先从全局的视觉看整体,接下来你会发现,组件的构成就是由这三部分组成。

组件类型

React天生就支持两种组件编写方式:类组件函数式组件,而这两种组件的差别在哪,何时使用它们?接下来先了解一下

何为类组件

所谓类组件,就是在ES6以来的class的写法,它继承于React.Component类,下面是一个类组件的示例:

js 复制代码
class chileComponent extends React.Component {
  // 维护自身组件的 state
  state = {
    name: "",
  };

  // 生命周期方法 didMount
  componentDidMount() {
    // 省略业务逻辑
  }

  // 自定义的实例方法(合成事件)
  changeName = (newName) => {
    // 更新 state
    this.setState({
      name: newName,
    });
  };

  // 生命周期方法 render
  render() {
    return (
      <div className="box_container">
        <p>{this.state.name}</p>
        <button onClick={this.changeName}>点我修改名称</button>
      </div>
    );
  }
}

何为函数式组件

顾名思义,就是以函数形式 存在的组件,返回JSX对象的形式给编译器进行编译。在React的发展历程中,函数式组件经过了从开始的无状态组件成长为具有React Hooks加持的有状态组件,这里讨论Hooks之前的组件。以下是一个经典的函数式组件:

js 复制代码
function childComponent(props) {
  const { name } = props;

  return (
    <div className="box_container">
      <p>{`该function 组件所接收到来自外界的数据是:[${name}]`}</p>
    </div>
  );
}

两者对比

从上面的两个例子中,我们可以看出它们存在以下的差异:

  • 类组件含有多个生命周期函数如componentDidUpdate,而函数式组件没有,意味着它不能够处理执行一些副作用操作
  • 类组件需要继承React.component,而函数式组件不需要
  • 类组件可以通过state维护自身的状态,而函数式组件只能接受来自外界的数据
  • 类组件中可以拿到自身组件的实例对象this,而函数式组件中不需要
  • 类组件创建过程具体更大的内存开销,而函数式组件没有实例化过程和生命周期,一定程度上性能会更佳

这样对比看起来是不是觉得类组件的功能比较强大呀,意味着比函数式组件好,应该选择使用类组件。

这样判断就有点过去片面了,凡事都有两面性,类组件虽然能力比较强大,但是也有不足的地方;而函数式组件看起来能力很有限,但是也有它存在的优点。应该怎么样去权衡选择呢,接下来深入认识这两种类型组件。

深入认识类组件

再来看看上面这个类组件的例子:

js 复制代码
class chileComponent extends React.Component {
  // 维护自身组件的 state
  state = {
    name: "",
  };

  // 生命周期方法 didMount
  componentDidMount() {
    // 省略业务逻辑
  }

  // 自定义的实例方法(合成事件)
  changeName = (newName) => {
    // 更新 state
    this.setState({
      name: newName,
    });
  };

  // 生命周期方法 render
  render() {
    return (
      <div className="box_container">
        <p>{this.state.name}</p>
        <button onClick={this.changeName}>点我修改名称</button>
      </div>
    );
  }
}

可以看到类组件提供了诸如componentDidMountgetSnapshotBeforeUpdateshouldComponentUpdate等生命周期钩子函数和状态State,它预制了很多现成的东西让开发者可以根据自己需要进行调度,不管你实际上用没用到我都会给你,至于你怎么使用我不管,这是你的事情,跟我无关!

用过mixins的朋友就知道,它可以混入很多工具方法或者状态给到子组件,而不管子组件是否真的需要。

也就是说当我用类组件渲染一个静态的节点时,声明周期函数和状态都会挂在到组件的实例上,实际上并不需要。另外,提供众多的API给到开发者调用,当使用不当的时候,极易造成组件渲染问题或者产生不可预知的bug,有人会说这是你开发者的问题,跟我React有半毛钱关系?的确是的,React无法决定开发者如何使用它,但是作为一个优秀的开源框架来说,在架构设计上减少开发者的心智负担是必须考虑的事情!

所以,在这个层面上得出一个结论是:**类组件它太重了!**在很多场景下,使用类组件会产生不必要的麻烦和性能开销,并且在组件封装层面,想要实现逻辑与组件解耦,需要学习更加高级的技巧如HOC高阶组件或者Render Props进一步封装。

深入认识函数式组件

来看看这个普通的函数式组件例子:

js 复制代码
function childComponent(props) {
  const { name } = props;

  return (
    <div className="box_container">
      <p>{`该function 组件所接收到来自外界的数据是:[${name}]`}</p>
    </div>
  );
}

可以看到,它就是一个普通函数,返回一个JSX对象,除了可以接受来自外界的Props数据,没有内置的状态管理能力,拥有轻量、灵活、易维护的特点,在React hooks诞生之前,它的应用场景非常有限!

总结

类组件拥有强大的生命周期钩子函数和状态管理能力,能够应对复杂的业务场景,但是在组件封装和逻辑管理方面也变的复杂繁琐,同时让维护和测试变的困难;

而类组件轻量、简单,函数一等公民的角色可以让组件变的容易测试,但它无法维护自身状态,很多场景下想用它但是用不了的尴尬地步,为了解决这种鸡肋的情况,React Hooks应运而生!

相关推荐
jacy1 分钟前
图片大图预览就该这样做
前端
林太白3 分钟前
Nuxt3 功能篇
前端·javascript·后端
YuJie4 分钟前
webSocket Manager
前端·javascript
Mapmost20 分钟前
Mapmost SDK for UE5 内核升级,三维场景渲染效果飙升!
前端
Mapmost22 分钟前
重磅升级丨Mapmost全面兼容3DTiles 1.1,3DGS量测精度跃升至亚米级!
前端·vue.js·three.js
wycode29 分钟前
Promise(一)极简版demo
前端·javascript
浮幻云月30 分钟前
一个自开自用的Ai提效VsCode插件
前端·javascript
DevSecOps选型指南31 分钟前
SBOM风险预警 | NPM前端框架 javaxscript 遭受投毒窃取浏览器cookie
前端·人工智能·前端框架·npm·软件供应链安全厂商·软件供应链安全工具
__lll_39 分钟前
Docker 从入门到实战:容器、镜像与 Compose 全攻略
前端·docker