React函数组件与类组件使用及优劣对比

目录
  • 一、类组件的问题
    • 原因一、因为this带来的问题:
      • 问题描述
      • 问题解析
    • 原因二、类组件代码量比函数组件多:
    • 原因三、类组件过于臃肿不易拆分:
  • 二、函数组件的问题
    • 挂载阶段:getDerviedStateFromProps VS 无
    • 挂载阶段:UNSAFE_componentWillMount VS 无
    • 挂载阶段:componentDidMount VS useEffect
    • render:
    • 生命周期,更新阶段:UNSAFE_componentWillRerciveProps VS 无
    • 生命周期,更新阶段:getDerviedStateFromProps VS 无
    • 生命周期,更新阶段:shouldComponentUpdate VS memo、useMemo、useCallback
    • 生命周期,更新阶段:UNSAFE_componentWillUpdate VS 无
    • render:
    • 生命周期,更新阶段:getSnapshotBeforeUpdate VS 无
    • 生命周期,更新阶段:componentDidUpdate VS 无
    • 生命周期,卸载阶段:componentWillUnmount VS useEffect
    • 其他,错误边界:componentDidCatch、static getDerivedStateFromError VS 无
  • 三、总结

一、类组件的问题

自从React推出Hooks之后,函数组件写法大行其道,而类组件写法日渐式微。为什么会这样呢? 我觉得有以下三个原因:

原因一、因为this带来的问题:

有一个著名的案例展示了类组件this带来的问题,下面我将其本土化复现一下这个案例。

import React from "react"

const ProfileFunction: React.FC<{goods:string}> = (props) => {
    const showMessage = () => {
        alert(`你下单的是“${props.goods}”!` )
    }
    const handleClick = () => {
        setTimeout(showMessage, 3 * 1000)
    }
    return (
        <button onClick={handleClick}>购买</button>
    )
}

class ProfileClass extends React.Component<
    { goods: string },  // props 类型
    {}  // state 类型
> {
    showMessage = () => {
        alert(`你下单的是“${this.props.goods}”!` )
    }
    handleClick = () => {
        setTimeout(this.showMessage, 3 * 1000)
    }
    render() {
        return <button onClick={this.handleClick}>购买</button>
    }
}

export default class App extends React.Component {
    state = {
        goods: '苹果',
    };
    render() {
        return (
            <>
                <label>
                    请选择:
                    <select
                        value={this.state.goods}
                        onChange={e => this.setState({ goods: e.target.value })}
                    >
                        <option value="苹果">苹果</option>
                        <option value="香蕉">香蕉</option>
                        <option value="西瓜">西瓜</option>
                    </select>
                </label>
                <h1>{this.state.goods}</h1>
                <p>
                    <ProfileFunction goods={this.state.goods} />
                    <b> (function)</b>
                </p>
                <p>
                    <ProfileClass goods={this.state.goods} />
                    <b> (class)</b>
                </p>
            </>
        )
    }
}

这里有在线案例,有兴趣的朋友可以在线体验一下这个案例。

问题描述

  • 函数组件:当用户选择苹果,点击购买后,再切换浏览香蕉,提示信息反馈用户下单的是苹果。
  • 类 组 件 :当用户选择苹果,点击购买后,再切换浏览西瓜,提示信息反馈用户下单的是西瓜!

问题解析

粗看函数组件和类组件的代码,都是返回一个按钮,该按钮3秒(模拟网络延迟)后会弹出一个alert提示用户下单的商品。为什么结果不一致呢? 参数props本身是不可变的,函数组件中的showMessage在3秒延迟后拿到的仍然是原来的props.goods。 但是类组件中实例的this是可变的,类组件中的showMessage在3秒延迟后去拿this.props.goods时,由于this发生了变化,所以造成取到的值不是原来的值。

原因二、类组件代码量比函数组件多:

这个从上面的案例中可见一斑,同样功能的函数组件代码量比类组件少一些。

原因三、类组件过于臃肿不易拆分:

类组件和函数组件最大的不同还在于代码思路方面的不同。类组件是面向对象编程思维方式,函数组件是面向过程编程思维方式。React的设计思路更推崇组合,而不是继承。在类组件中大量使用继承会造成组件过重,功能难以拆分。

二、函数组件的问题

函数组件以前被叫做无状态组件,就是因为函数组件内部不能保存state。自从react官方推出各类hooks后,函数式组件变得越来越流行。react官方宣称将来会推出更多hooks以实现所有类组件的功能,不过这个flag立了挺久的,至今还有很多没有实现。 下面来按生命周期的顺序盘点一下类组件的方法与函数组件对应的hooks。

挂载阶段:getDerviedStateFromProps VS 无

  • 该方法用于在props被传入后根据props更新state。
  • 函数组件中也可以写代码根据props更新state,但这样做会造成重复渲染。如果遇到需要根据props更新state的情况,应该考虑做状态提升。如果你发现在某个组件中必须要根据props更新state又无法做状态提升,那么该组件应该写成类式组件,而不是函数式组件。

挂载阶段:UNSAFE_componentWillMount VS 无

  • 该方法用于在组件挂载之前处理一些逻辑,但它在异步渲染模式下容易造成重复调用,react官方已将其标记为废弃。
  • 函数组件可以无视该方法。

挂载阶段:componentDidMount VS useEffect

  • 该方法用于在组件挂载以后执行副作用操作,如发起网络请求、设置计时器、创建订阅等。
  • 函数组件有useEffect。

render:

  • 在类组件的render方法中返回要渲染的内容。render里不能有副作用和setState!
  • 函数组件的return和类组件render方法的return效果一致。

生命周期,更新阶段:UNSAFE_componentWillRerciveProps VS 无

  • 该方法作用跟getDerviedStateFromProps的一样,都是在组件挂载之前处理一些逻辑,但react官方已将其标记为废弃。
  • 函数组件可以无视该方法。

生命周期,更新阶段:getDerviedStateFromProps VS 无

同挂载阶段的同名方法一样。

生命周期,更新阶段:shouldComponentUpdate VS memo、useMemo、useCallback

  • 该方法返回true表示需要更新、返回false表示无需更新。可在此添加判断条件做性能优化,另外PureComponent实现原理也相同。
  • 函数组件对应的hooks有很多,常用的有memo、useMemo、useCallback,同样可以做性能优化。

生命周期,更新阶段:UNSAFE_componentWillUpdate VS 无

  • 该方法原来在组件重新渲染之前做一些操作,react官方已将其标记为废弃。
  • 函数组件可以无视该方法。

render:

同挂载阶段一样。

生命周期,更新阶段:getSnapshotBeforeUpdate VS 无

  • 该方法在最近一次渲染输出(提交到DOM节点)之前调用。它使得组件能在发生更改之前从DOM中捕获一些信息(如滚动位置等)。此生命周期方法的任何返回值将作为参数传递给componentDidUpdate()。此用法并不常见,但它可能出现在UI 处理中,如以特殊方式处理滚动位置的聊天线程等。
  • 函数组件无该方法对应的hooks。

生命周期,更新阶段:componentDidUpdate VS 无

  • 组件更新后会立即调用该方法,首次渲染不会调用。当组件更新后,可以在此处对DOM进行操作。注意:在该方法中慎用setState,如果要用必须将其包裹在条件语句里。
  • 函数组件无该方法对应的hooks,因为React本身设计是减少直接操作DOM,在React中除了useRef外直接操作DOM的场景很少,函数组件没有该方法对应的hooks不算什么问题。

生命周期,卸载阶段:componentWillUnmount VS useEffect

  • 该方法会在组件卸载及销毁之前直接调用。在此方法中执行必要的清理操作,例如:清除计时器、取消网络请求或清除订阅等。
  • 函数组件有useEffect。

其他,错误边界:componentDidCatch、static getDerivedStateFromError VS 无

  • 在类组件中定义了static getDerivedStateFromError或componentDidCatch这两个生命周期方法中的任意一个或两个时,那么它就变成一个错误边界。当抛出错误后,请使用static getDerivedStateFromError渲染备用UI,使用componentDidCatch打印错误信息。
  • 函数组件无错误边界对应的hooks

三、总结

函数组件和类组件各有优势。类组件功能最为完备和强大,某些特殊用途(如错误边界)组件只能写成类式组件。函数组件没有this困扰且代码简洁,大部分的普通组件都可以写成函数组件。

到此这篇关于React函数组件与类组件使用及优劣对比的文章就介绍到这了,更多相关React函数组件与类组件 内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 详解使用React.memo()来优化函数组件的性能

    React核心开发团队一直都努力地让React变得更快.在React中可以用来优化组件性能的方法大概有以下几种: 组件懒加载(React.lazy(...)和<Suspense />) Pure Component shouldComponentUpdate(...){...}生命周期函数 本文还会介绍React16.6加入的另外一个专门用来优化函数组件(Functional Component)性能的方法: React.memo. 无用的渲染 组件是构成React视图的一个基本单元.有些组件

  • react纯函数组件setState更新页面不刷新的解决

    目录 问题描述: 原因分析: 解决方案: 补:react中,hooks钩子时useState更新不渲染组件的问题 问题描述: const [textList, setTextList] = useState(原数组); setTextList(新数组); 当修改原数组时,如果原数组是个深层数组(不只一层),使用setTextList修改时,不会触发页面刷新 原因分析: 这个涉及到可变对象he不可变对象的知识,在vue和react中,如果更新可变对象时,可能会引起视图更新,这是因为,vue和rea

  • React函数式组件与类组件的不同你知道吗

    目录 区别 其他区别 总结 区别 区别 函数组件 类组件 生命周期 无 有 this 无 有 state 无 有 改变state React Hooks:useState this.setState() 性能 高(不用实例化) 低(需要实例化) 其他区别 ProfilePageClass.js import React from 'react'; class ProfilePageClass extends React.Component { showMessage = () => { aler

  • React函数组件与类组件使用及优劣对比

    目录 一.类组件的问题 原因一.因为this带来的问题: 问题描述 问题解析 原因二.类组件代码量比函数组件多: 原因三.类组件过于臃肿不易拆分: 二.函数组件的问题 挂载阶段:getDerviedStateFromProps VS 无 挂载阶段:UNSAFE_componentWillMount VS 无 挂载阶段:componentDidMount VS useEffect render: 生命周期,更新阶段:UNSAFE_componentWillRerciveProps VS 无 生命周

  • React函数组件和类组件的区别及说明

    目录 React函数组件和类组件区别 函数组件 类组件 区别 React函数式组件和类组件的优缺点 1.类组件的性能消耗比较大 2.函数式组件性能消耗小 React函数组件和类组件区别 定义组件有两个要求: 组件名称必须以大写字母开头 组件的返回值只能有一个根元素 函数组件 function Welcome (props) {   return <h1>Welcome {props.name}</h1> } ReactDOM.render(<Welcome name='rea

  • react生命周期(类组件/函数组件)操作代码

    1.react代码模式分为两种 类组件和函数组件(生命周期也有所不同) 2.类组件(写法如下) import React from 'react' export default class App1 extends React.Component{ state = { username:'', password:'' } setUser = (event) => { this.setState({username:event.target.value}) } setPass = (event)

  • 使用 React Hooks 重构类组件的示例详解

    目录 1. 管理和更新组件状态 2. 状态更新后的操作 3. 获取数据 4. 卸载组件时清理副作用 5.  防止组件重新渲染 6. Context API 7. 跨重新渲染保留值 8. 如何向父组件传递状态和方法? 9. 小结 最初,在 React 中可以使用 createClass 来创建组件,后来被类组件所取代.在 React 16.8 版本中,新增的 Hooks 功能彻底改变了我们编写 React 程序的方式,使用 Hooks 可以编写更简洁.更清晰的代码,并为创建可重用的有状态逻辑提供了

  • React 组件转 Vue 组件的命令写法

    基于目前React和Vue比较火,开发react-to-vue工具的目的是为了进一步提高组件的可复用用性,让组件复用不仅仅局限在一个框架里面 简介 对于react-to-vue工具,转化的是基本的react component,而不是全部的react应用.而基本react component的定义更多是基于props和state来渲染的组件,其中也可以包括发请求. 本文先介绍两个框架的组件共性和不兼容的地方,再介绍react-to-vue的使用和原理.在实际业务中,陆金所100多个的react基

  • React 函数式组件和类式组件详情

    目录 前言 1. 函数式组件 2. 类式组件 前言 React 是 组件化的 的 JS 库,组件化 也是 React 的核心思想.使用 React 可以构建管理自身状态的封装组件,然后对其组合以构成复杂的 UI.那么什么是组件呢? 组件是用来实现局部功能效果的代码和资源的集合,包括 html / css / js/ image 等,组件的作用是 简化代码.复用代码.提高运行效率. React 里主要有两种类型的组件: 函数式组件 => 基于函数: 类式组件 => 基于类: 1. 函数式组件 函

  • react函数组件useState异步,数据不能及时获取到的问题

    目录 react useState异步,数据不能获取到 问题 解决方法一 react中useState的使用及注意事项 基本使用 注意事项 react useState异步,数据不能获取到 useState() 属于异步函数,在useState() 第一次存储的时候,值会存储不上 因为react中state的更新是异步的,我们setState后,react不会立刻对值进行改变,而是将其暂时放入pedding队列中.react会合并多个state,然后值render一次,所以不要在循环中使用use

  • react-native 父函数组件调用类子组件的方法(实例详解)

    react-native 父函数组件调用类子组件的方法,代码如下所示: import React, {Component} from 'react'; import {Text, View, TouchableOpacity} from 'react-native'; // 父 let child onRefbbb = (ref) => { child = ref } clickccc = () => { child.myName() } const Parent =()=> { ret

  • React函数组件hook原理及构建hook链表算法详情

    目录 写在前面的小结 Demo fiber hook 链表 hook 对象及其属性介绍 useState Hook 对象 useRef Hook useEffect.useLayoutEffect 以及 useImperativeHandle useMemo useCallback 构建 Hook 链表的源码 renderWithHooks 函数组件执行 构建 hook 链表的算法 mountWorkInProgressHook 构建 hook 链表算法 updateWorkInProgress

随机推荐