React:类组件与函数组件

2025-05-24

React:类组件与函数组件

刚开始使用 React 的时候,我主要使用函数组件,尤其是因为我读到过有人说 Class 组件老旧过时。但当我开始专业地使用 React 时,我意识到我错了。Class 组件现在依然非常流行。

因此,我决定写一种类组件和函数组件之间的比较,以便更好地理解它们的异同。


目录


类组件

这是一个利用的类组件stateprops如下render所示:

class Hello extends React.Component {

    constructor(props) {
    super(props);
    this.state = {
      name: props.name
    };
  }

  render() {
    return <h1>Hello, {this.state.name}</h1>;
  }
}

// Render

ReactDOM.render(
  Hello,
  document.getElementById('root')
);
Enter fullscreen mode Exit fullscreen mode

您可以在相关来源中找到有关此内容的更多信息:

渲染

假设 <div> 你的 HTML 文件中有这样一段内容:

<div id="root"></div>
Enter fullscreen mode Exit fullscreen mode

我们可以用如下方式element来代替 来渲染divroot id

const element = <h1>Hello, world</h1>;
ReactDOM.render(element, document.getElementById('root'));
Enter fullscreen mode Exit fullscreen mode

关于 React 组件,我们通常会导出一个组件并在另一个文件中使用它:

  • Hello.jsx
import React, { Component } from 'react';

class Hello extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

export default Hello;
Enter fullscreen mode Exit fullscreen mode
  • main.js
import React from 'react';
import ReactDOM from 'react-dom';
import Hello from './app/Hello.jsx';

ReactDOM.render(<Hello />, document.getElementById('root'));
Enter fullscreen mode Exit fullscreen mode

这就是类组件在 Web 浏览器上的呈现方式。

现在,渲染和安装之间存在差异,Brad Westfall对此进行了很好的总结

“渲染”是指任何时候调用函数组件(或基于类的渲染方法),并返回一组用于创建 DOM 的指令。
“挂载”是指 React 首次“渲染”组件,并根据这些指令实际构建初始 DOM。

状态

状态是一个 JavaScript 对象,包含有关组件当前状况的信息。

要初始化类组件状态,我们需要使用constructor

class Hello extends React.Component {

    constructor() {
    this.state = {
      endOfMessage: '!'
    };
  }

  render() {
    return <h1>Hello, {this.props.name} {this.state.endOfMessage}</h1>;
  }
}
Enter fullscreen mode Exit fullscreen mode

关于此内容的相关资料:

注意:我们不应该直接修改状态,因为它不会触发组件的重新渲染:

this.state.comment = 'Hello'; // Don't do this
Enter fullscreen mode Exit fullscreen mode

相反,我们应该使用以下setState()方法:

this.setState({comment: 'Hello'});
Enter fullscreen mode Exit fullscreen mode

如果我们的当前状态依赖于前一个状态,并且setState是异步的,我们应该考虑前一个状态:

this.setState(function(prevState, prevProps) {
  return {
    counter: prevState.counter + prevProps.increment
  };
});
Enter fullscreen mode Exit fullscreen mode

关于此内容的相关资料:

常见的陷阱

如果我们需要设置具有嵌套对象的状态,则我们应该扩展该对象中的所有嵌套级别:

this.setState(prevState => ({
    ...prevState,
    someProperty: {
        ...prevState.someProperty,
        someOtherProperty: {
            ...prevState.someProperty.someOtherProperty, 
            anotherProperty: {
               ...prevState.someProperty.someOtherProperty.anotherProperty,
               flag: false
            }
        }
    }
}))
Enter fullscreen mode Exit fullscreen mode

[immutability-helper](https://github.com/kolodny/immutability-helper)这可能会变得麻烦,因此建议使用该包。

关于此内容的相关资料:

在我了解之前,我以为设置新的对象属性总是会保留未设置的属性,但对于嵌套对象来说并非如此(这有点合乎逻辑,因为我会用另一个对象覆盖一个对象)。这种情况发生在我之前展开对象,然后修改它的某个属性时:

> b = {item1: 'a', item2: {subItem1: 'y', subItem2: 'z'}}
//-> { item1: 'a', item2: {subItem1: 'y', subItem2: 'z'}}
> b.item2 = {...b.item2, subItem1: 'modified'}
//-> { subItem1: 'modified', subItem2: 'z' }
> b
//-> { item1: 'a', item2: { subItem1: 'modified', subItem2: 'z' } }
> b.item2 = {subItem1: 'modified'} // Not OK
//-> { subItem1: 'modified' }
> b
//-> { item1: 'a', item2: { subItem1: 'modified' } }
Enter fullscreen mode Exit fullscreen mode

但是,当我们有嵌套对象时,我们需要使用多个嵌套展开,这会导致代码重复。这时 immutability-helper 就派上用场了。

您可以在此处找到有关此内容的更多信息

道具

如果我们想要访问propsconstructor我们需要使用以下命令调用父类构造函数super(props)

class Button extends React.Component {
  constructor(props) {
    super(props);
    console.log(props);
    console.log(this.props);
  }
  // ...
}
Enter fullscreen mode Exit fullscreen mode

关于此内容的相关资料:

请记住,使用props设置初始状态 是 React 的反模式。过去,我们可以使用该componentWillReceiveProps方法来设置初始状态,但现在它已被弃用

class Hello extends React.Component {

    constructor(props) {
    super(props);

    this.state = {
      property: this.props.name, // Not recommended, but OK if it's just used as seed data.
    };
  }

  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}
Enter fullscreen mode Exit fullscreen mode

如果我们明确表示仅用作组件内部控制状态的种子数据,那么使用props它来初始化并不是反模式。stateprop

关于此内容的相关资料:

生命周期方法

类组件没有hooks;它们有生命周期方法。

  • render()
  • componentDidMount()
  • componentDidUpdate()
  • componentWillUnmount()
  • shouldComponentUpdate()
  • static getDerivedStateFromProps()
  • getSnapshotBeforeUpdate()

您可以在这里了解有关生命周期方法的更多信息:


函数组件

函数组件

函数组件使用propsstate和 的方式如下render

function Welcome(props) {
    const [timeOfDay, setTimeOfDay] = useState('morning');

    return <h1>Hello, {props.name}, good {timeOfDay}</h1>;
}

// or

const Welcome = (props) => {
    const [timeOfDay, setTimeOfDay] = useState('morning');

    return <h1>Hello, {props.name}, good {timeOfDay}</h1>;
}

// Render

const element = <Welcome name="Sara" />;

ReactDOM.render(
  element,
  document.getElementById('root')
);
Enter fullscreen mode Exit fullscreen mode

渲染

渲染函数组件的方式与类组件相同:

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

const element = <Welcome name="Sara" />;

ReactDOM.render(
  element,
  document.getElementById('root')
);
Enter fullscreen mode Exit fullscreen mode

来源:

状态

说到状态,函数组件与类组件有很大不同。我们需要定义一个包含两个主要元素的数组:状态值和用于更新状态的函数。然后,我们需要将钩子赋值useState给该数组,并在过程中初始化状态:

import React, { useState } from 'react';

function Example() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

钩子是函数组件允许我们以 与类组件类似的方式 useState使用组件的方式。statethis.state

记住:函数组件使用hooks。根据官方文档:

什么是 Hook?  Hook 是一种特殊的函数,可以让你“钩住” React 的功能。例如,  useState Hook 可以让你向函数组件添加 React 状态。我们稍后会学习其他 Hook。

什么时候应该使用 Hook? 如果你编写了一个函数组件,并意识到需要为其添加一些状态,以前你必须将其转换为类。现在,你可以在现有的函数组件中使用 Hook。

要读取函数组件的状态,我们可以使用useState在函数声明中使用时定义的变量(count在我们的示例中)。

<p>You clicked {count} times</p>
Enter fullscreen mode Exit fullscreen mode

在类组件中,我们必须做这样的事情:

<p>You clicked {this.state.count} times</p>
Enter fullscreen mode Exit fullscreen mode

setCount每次我们需要更新状态时,我们都应该使用新状态的值调用我们定义的函数(在本例中)。

<button onClick={() => setCount(count + 1)}>
  Click me
</button>
Enter fullscreen mode Exit fullscreen mode

同时,在类组件中我们使用this关键字,后跟state要更新的属性:

<button onClick={() => this.setState({ count: this.state.count + 1 })}>
  Click me
</button>
Enter fullscreen mode Exit fullscreen mode

资料来源:

道具

最后,props在函数组件中使用非常简单:我们只需将它们作为组件参数传递:

function Avatar(props) {
  return (
    <img className="Avatar"
      src={props.user.avatarUrl}
      alt={props.user.name}
    />
  );
}
Enter fullscreen mode Exit fullscreen mode

来源:

结论

决定使用类组件还是函数组件取决于具体情况。据我所知,专业环境会将类组件用作“主要”组件,而将函数组件用作较小的特定组件。不过,根据你的项目情况,情况可能并非如此。

我很想看到在特定情况下使用类和函数组件的示例,所以不要羞于在评论部分分享它们。


🗞️新闻通讯 - 如果您想了解我的最新文章和有趣的软件开发内容,请订阅我的新闻通讯

🐦TWITTER——在Twitter上关注

文章来源:https://dev.to/colocodes/react-class-components-vs-function-components-23m6
PREV
使用 Notion 组织编程主题
NEXT
避免对着电脑大喊大叫的解决问题技巧