重新认识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应运而生!

相关推荐
素**颜3 分钟前
uniapp 基于xgplayer(西瓜视频) + renderjs开发,实现APP视频播放
javascript·uni-app·音视频
m0_748251085 分钟前
docker安装nginx,docker部署vue前端,以及docker部署java的jar部署
java·前端·docker
我是ed18 分钟前
# thingjs 基础案例整理
前端
Ashore_24 分钟前
从简单封装到数据响应:Vue如何引领开发新模式❓❗️
前端·vue.js
落魄实习生26 分钟前
小米路由器开启SSH,配置阿里云ddns,开启外网访问SSH和WEB管理界面
前端·阿里云·ssh
bug丸34 分钟前
v8引擎垃圾回收
前端·javascript·垃圾回收
安全小王子35 分钟前
攻防世界web第三题file_include
前端
&活在当下&37 分钟前
ref 和 reactive 的用法和区别
前端·javascript·vue.js
百事老饼干40 分钟前
VUE前端实现防抖节流 Lodash
前端
web Rookie44 分钟前
React 高阶组件(HOC)
前端·javascript·react.js