React中类组件和函数组件的理解和区别

react代码模块分为类组件和函数组件。

语法和定义内部状态管理生命周期性能可读性和维护性上下文集成状态管理库等角度对比React中类组件和函数组件。

1、语法和定义

类组件:

使用ES6 的类(class )语法定义的 React 组件。它们具有更复杂的功能,特别是在 React 16.8 之前,它们是唯一能够使用状态(state)和生命周期方法的组件。

特点:

  • 使用class 关键字定义,并继承自React.Component

  • 能够使用state来管理组件的内部状态。

  • 可以使用生命周期方法,如 componentDidMountcomponentDidUpdatecomponentWillUnmount 等。

  • 通过this.props 来访问传递给组件的属性(props)。

    import React, { Component } from 'react';

    class HelloComponent extends Component {
    constructor(props) {
    super(props);
    this.state = {
    count: 0
    };
    }

    increment = () => {
      this.setState({ count: this.state.count + 1 });
    }
    
    render() {
      return (
        <div>
          <p>Count: {this.state.count}</p>
          <button onClick={this.increment}>Increment</button>
        </div>
      );
    }
    

    }

    export default HelloComponent;

函数组件(Function Component):

函数组件是使用 JavaScript 函数定义的React 组件。自React 16.8 以来,函数组件通过引入 Hooks 可以实现状态管理和副作用处理,功能上已经与类组件基本等价。

特点:

  • 使用 JavaScript函数定义,通常是更简单和推荐的方式。

  • 在函数组件中,无法直接使用 this,而是通过 Hooks (如> useStateuseEffect)来管理状态和副作用。

  • 更加简洁,通常用于无状态组件,但在有状态需求时也可以使用 Hooks

    import React, { useState } from 'react';

    function HelloComponent() {
    const [count, setCount] = useState(0);

    const increment = () => {
      setCount(count + 1);
    };
    
    return (
      <div>
        <p>Count: {count}</p>
        <button onClick={increment}>Increment</button>
      </div>
    );
    

    }

    export default HelloComponent;

2、 内部状态管理

类组件:

使用类组件时,可以通过组件的内部状态(state)来管理组件的数据。

import React from 'react';
 
class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }
 
  render() {
    return (
      <div>
        <p>Count: {this.state.count}</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>Increase</button>
      </div>
    );
  }
}
 
export default Counter;

函数组件(Function Component):

函数组件可以使用hooks(React 16.8+)来管理内部状态。

useState钩子:

import React, { useState } from 'react';
 
function Counter() {
  const [count, setCount] = useState(0);
 
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increase</button>
    </div>
  );
}
 
export default Counter;

useReducer钩子(适用于复杂的状态逻辑):

import React, { useReducer } from 'react';
 
function Counter() {
  const [count, dispatch] = useReducer((state, action) => {
    switch (action.type) {
      case 'increment':
        return state + 1;
      case 'decrement':
        return state - 1;
      default:
        throw new Error();
    }
  }, 0);
 
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => dispatch({ type: 'increment' })}>Increase</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>Decrease</button>
    </div>
  );
}
 
export default Counter;

3、 生命周期

类组件:

类组件生命周期(三个阶段:挂载阶段,更新阶段,卸载阶段)

挂载阶段执行顺序 :constructor ->componentWillMount ->render ->componentDidMount

更新阶段执行顺序: shouldComponentUpdate ->componentWillUpdate ->render ->componentDidUpdate

销毁阶段: componentWillUnmount

import React  from "react";
import {Link} from 'react-router-dom'
class Demo extends React.Component{
  
    constructor(props){
        super(props)
        console.log("constructor")
    }
    state = {
        num:1
    }
    UNSAFE_componentWillMount(){
        console.log("componentWillMount")
    }
    componentDidMount(){
        console.log("componentDidMount")
    }
    shouldComponentUpdate(){
      console.log('shouldComponentUpdate')
      return true
    }
    UNSAFE_omponentWillUpdate(){
        console.log("componentWillUpdate")
    }
    componentDidUpdate(){
        console.log("componentDidUpdate")
    }
    componentWillUnmount(){
        console.log("componentWillUnmount")
    }
    Submit = () =>  {
        this.setState({num:this.state.num+=1})
    }
    render(){
        console.log('render')
        return(
            <>
              <Link to='/app1'>App1</Link>
              //这里替换成自己的即可
              <h3>{this.state.num}</h3>
              <button onClick={this.Submit}>改变</button>
            </>
        )
    }
}
export default Demo

函数组件(Function Component):

函数组件本质没有生命周期,但是我们通过Hooks来模仿类组件当中的生命周期(也是三个阶段)

import { useState ,useEffect} from "react"
function App1 (){
    const [username ,setUsername] = useState('')
    const setChange = event => {
        setUsername(event.target.value);
      };
        // useEffect  =  vue mounted 区别是只要视图更新就变化 感觉类似watch 但是他又是初始化的 时候第一个
        //  useEffect(()=>{},[])
        useEffect(()=>{
          console.log('模拟componentDidMount第一次渲染', username)
            return () =>{
                console.log('模拟componentWillUnmount执行销毁后')
            }
        },[username])
    return(
        <>
          <input value={username} onChange={setChange}></input>
        </>
    )
}
export default  App1

4、 性能

React类组件和函数组件之间的性能对比主要关注以下几个方面:

|-------------------|----------------------------------------|------------------------------------|
| 角度 | 类组件 | 函数组件 |
| 渲染性能 | 在渲染时会进行shouldComponentUpdate生命周期检查 | 需要使用React.memo或自定义比较逻辑来避免不必要的重渲染 |
| 状态更新 | 可以在shouldComponentUpdate中实现更细粒度的更新检查 | 需要使用React.memo或自定义比较逻辑来避免不必要的重渲染 |
| 组件的状态和生命周期复杂性 | 可能会引入更多的对象和函数,这可能会影响GC(垃圾回收) | - |
| 内存占用 | 因为其实例和可能的引用,可能会占用更多内存 | - |

5、 可读性和维护性

可读性和维护性是评估代码质量的重要指标。

  • 类组件 的可读性和维护性可能不如函数组件。类组件中的this指向以及生命周期方法(如componentDidMount)可能会增加理解和维护的难度。

  • 函数组件的可读性和维护性较好,因为它们就像纯函数,更接近于数学函数的定义,更容易理解和维护。

  • 对于简单的组件,使用函数组件是首选,因为它们更简单且易于理解。

  • 对于需要管理状态或生命周期事件的组件,类组件是必须的。

  • 可以使用hooks(React 16.8+)来编写函数组件,它们可以让你在不编写类的情况下使用state和其他React特性。

如:类组件

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }
 
  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>
    );
  }
}

函数组件(Function Component):

function MyComponent() {
  const [count, setCount] = React.useState(0);
 
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}

在这个例子中,函数组件**MyComponent** 通过React.useState hook管理了状态,使得它的定义更接近于类组件的行为,同时更易于阅读和维护。

6、 上下文

类组件 :可以通过**this.context** 访问上下文。需要在类组件上使用**static contextType** 声明期望访问的上下文,或者使用**contextTypes**属性进行类型检查(使用React 16.6之前的API)。

import React, { Component } from 'react';
 
class MyClassComponent extends Component {
  static contextType = MyContext; // 使用最新的context API
 
  componentDidMount() {
    const data = this.context; // 访问上下文
  }
 
  render() {
    return <div>My Class Component</div>;
  }
}

函数组件(Function Component) :可以使用**useContext** 钩子从React获取上下文。

import React, { useContext } from 'react';
 
function MyFunctionComponent() {
  const contextData = useContext(MyContext); // 使用hooks获取上下文
 
  return <div>My Function Component</div>;
}

注意:**useContext**只能在函数组件或者自定义钩子中使用。类组件不能使用这种方式访问上下文。

7、 集成状态管理库

React 中,类组件函数组件 可以使用状态管理库来管理复杂的状态。常见的状态管理库有Redux、MobX、Context API等。

8、总结类组件、函数组件的优缺点

|----|-------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------|
| 角度 | 类组件 | 函数组件 |
| 优点 | 1. 完全控制:可以访问所有React生命周期的钩子。 2. 状态(state)管理:可以维护和更新组件的状态。 3. 复杂交互:类组件可以管理更复杂的交互,如动画、表单等。 4. 性能优化:使用shouldComponentUpdate生命周期方法来优化渲染。 | 1. 轻量级:函数组件不涉及创建类实例所带来的开销,并且它们自然阻止了this上的问题。 2. 简单:代码通常更简洁,更容易编写和维护。 3. Hooks:React 16.8+引入了Hooks,使函数组件可以使用状态(state)和其他React特性。 |
| 缺点 | 1. 与函数组件相比,更多的开销,如创建类实例、绑定this等。 2. 容易产生this指向问题,需要手动绑定this。 | 1. 不能访问整个组件生命周期的所有钩子,例如componentDidCatch和componentDidMount。 2. 对于复杂的交云,可能需要额外的库或自定义钩子。 3. 不能使用ref属性,因为React无法在每次渲染时返回同一个函数实例。 |

相关推荐
开心工作室_kaic43 分钟前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
刚刚好ā43 分钟前
js作用域超全介绍--全局作用域、局部作用、块级作用域
前端·javascript·vue.js·vue
沉默璇年2 小时前
react中useMemo的使用场景
前端·react.js·前端框架
yqcoder2 小时前
reactflow 中 useNodesState 模块作用
开发语言·前端·javascript
2401_882727572 小时前
BY组态-低代码web可视化组件
前端·后端·物联网·低代码·数学建模·前端框架
SoaringHeart3 小时前
Flutter进阶:基于 MLKit 的 OCR 文字识别
前端·flutter
会发光的猪。3 小时前
css使用弹性盒,让每个子元素平均等分父元素的4/1大小
前端·javascript·vue.js
天下代码客3 小时前
【vue】vue中.sync修饰符如何使用--详细代码对比
前端·javascript·vue.js
猫爪笔记3 小时前
前端:HTML (学习笔记)【1】
前端·笔记·学习·html
前端李易安4 小时前
Webpack 热更新(HMR)详解:原理与实现
前端·webpack·node.js