返回顶部
首页 > 资讯 > 前端开发 > JavaScript >React函数组件与类的区别有哪些
  • 616
分享到

React函数组件与类的区别有哪些

React函数组件与类React函数组件 2022-11-13 18:11:26 616人浏览 薄情痞子
摘要

目录一、函数式组件捕获了渲染所用的值二、闭包让类组件成为拥有特定props和state的渲染三、区分useState与useRef的使用首先我们要知道的是,项目性能能主要取决于代码的

首先我们要知道的是,项目性能能主要取决于代码的作用,而不是选择函数式还是类组件。尽管优化策略各有略微不同,但它们之间的性能差异可以忽略不计。

一、函数式组件捕获了渲染所用的值

首先我们来看下面这个组件:

function App(props) {
  const showMessage = () => {
    alert('Hello' + props.user);
  };
  const handleClick = () => {
    setTimeout(showMessage, 3000);
  };
  return (
    <button onClick={handleClick}>Say</button>
  );
}

它渲染了一个利用来模拟网络请求,然后显示一个确认警告的按钮。例如,如果是传递进来的 props.user 是 jie,那么三秒后就会弹出 Hello jie。

那么我们用类应该怎么写这个组件呢?一个简单的重构可能就象这样:

class App extends React.Component {
  showMessage = () => {
    alert('Hello' + this.props.user);
  };
  handleClick = () => {
    setTimeout(this.showMessage, 3000);
  };
  render() {
    return <button onClick={this.handleClick}>Say</button>;
  }
}

我们通常做代码重构的时候都认为他们两个是等效的,但是事实真的如此吗,我们很少注意到它们之间的含义。

下面我们新建一个 react 项目,在 src下新建两个组件,一个 classComponent 组件,一个是 functionComponent 组件。代码就是上面我们写的这两个组件,只不过内容稍有区别:

classComponent:

import React from 'react';
class ProfilePage extends React.Component {
  showMessage = () => {
    alert('你选择了 ' + this.props.user);
  };
  handleClick = () => {
    setTimeout(this.showMessage, 3000);
  };
  render() {
    return <button onClick={this.handleClick}>选择</button>;
  }
}
export default ProfilePage;

functionComponent:

import React from 'react';
function ProfilePage(props) {
  const showMessage = () => {
    alert('你选择了 ' + props.user);
  };
  const handleClick = () => {
    setTimeout(showMessage, 3000);
  };
  return (
    <button onClick={handleClick}>选择</button>
  );
}
export default ProfilePage;

在 app.js 中我们将这两个组件引入:

import React from "react";
import ReactDOM from "react-dom";
import ProfilePageFunction from './functionComponent';
import ProfilePageClass from './classComponent';
export default class App extends React.Component {
  state = {
    user: '小杰',
  };
  render() {
    return (
      <>
        <label>
          <b>选择你想要拜访的朋友</b>
          <select
            value={this.state.user}
            onChange={e => this.setState({ user: e.target.value })}
          >
            <option value="小杰">小杰</option>
            <option value="小尚">小尚</option>
            <option value="小宁">小宁</option>
          </select>
        </label>
        <h1>欢迎来到 {this.state.user}的 家!</h1>
        <p>
          <ProfilePageFunction user={this.state.user} />
          <b> (这是来自函数式组件的)</b>
        </p>
        <p>
          <ProfilePageClass user={this.state.user} />
          <b> (这是来自类组件的)</b>
        </p>
      </>
    )
  }
}

运行项目,科研看到这样的界面:

当我们单击上面的按钮时,执行的就是函数式组件,点击下面的按钮时,执行的就是类。如果按照我们以往的思路,他们二者都会有相同的结果,但事实真的如此吗?

我们按照下面的顺序执行:

1. 点击函数式组件按钮

2. 在点击后立刻切换想要拜访的朋友

函数式组件的执行结果如下:

页面弹出的还是我们当时选择的值

同样的操作我们再试一下类组件:

现在页面弹出的就是我们实时更改的值了。

在这个例子中,第一个行为是正确的。因为最开始我选择要拜访小杰点击了确定发出了命令,然后我再切换到小尚,但是我并没有点击确定,我的组件不应该混淆我要拜访的人。在这里,类组件的实现很明显是错误的。

所以为什么我们的例子中类组件会有这样的表现?

让我们来仔细看看我们类组件中的方法:showMessage

showMessage = () => {
    alert('你选择了 ' + this.props.user);
  };

这个类方法从中读取数据。在 React 中 Props 是不可变的,所以他们永远不会改变。然而,this是,而且永远是,可变的。

事实上,这就是类组件存在的意义。React本身会随着时间的推移而改变,以便你可以在渲染方法以及生命周期方法中得到最新的实例。所以如果在请求已经发出的情况下我们的组件进行了重新渲染,将会改变。

我们的组件属于一个拥有特定 props 和 state 的特定渲染。

然而,调用一个回调函数读取 的 timeout 会打断这种关联。我们的回调并没有与任何一个特定的渲染绑定在一起,所以它失去了正确的 props。

二、闭包让类组件成为拥有特定props和state的渲染

我们想要以某种方式“修复”拥有正确 props 的渲染与读取这些 props 的回调之间的联系。它们在类的某个地方被弄丢了。

一种方法是在调用事件之前读取,然后将他们显式地传递到timeout回调函数中去:

import React from 'react';
class ProfilePage extends React.Component {
  showMessage = (user) => {
    alert('你选择了 ' + user);
  };
  handleClick = () => {
    const {user} = this.props;
    setTimeout(() => this.showMessage(user), 3000);
  };
  render() {
    return <button onClick={this.handleClick}>确定</button>;
  }
}
export default ProfilePage;

这种方法会起作用。然而,这种方法使得代码明显变得更加冗长,并且随着时间推移容易出错。如果我们需要的不止是一个props怎么办?如果我们还需要访问state怎么办?

然而,如果我们能利用javascript闭包的话问题将迎刃而解。

通常来说我们会避免使用闭包,但是在React中,props和state是不可变的,这就消除了闭包的一个主要缺陷。

这就意味着如果你在一次特定的渲染中捕获那一次渲染所用的props或者state,你会发现他们总是会保持一致,就如同你的预期那样。

class ProfilePage extends React.Component {
  render() {
    const props = this.props;
    const showMessage = () => {
      alert('你选择了 ' + props.user);
    };
    const handleClick = () => {
      setTimeout(showMessage, 3000);
    };
    return <button onClick={handleClick}>确定</button>;
  }
}

你在渲染的时候就已经“捕获”了props。这样,在它内部的任何代码(包括)都保证可以得到这一次特定渲染所使用的props。上面的例子是正确的,但是看起来很奇怪。如果你在方法中定义各种函数,而不是使用class的方法,那么使用类的意义在哪里?

所以这个时候我们就明白了函数式组件和类组件的区别:

function ProfilePage({ user }) {
  const showMessage = () => {
    alert('Followed ' + user);
  };
  const handleClick = () => {
    setTimeout(showMessage, 3000);
  };
  return (
    <button onClick={handleClick}>Follow</button>
  );
}

当父组件使用不同的props来渲染时,React会再次调用函数。但是我们点击的事件处理函数,"属于"具有自己的值的上一次渲染,并且回调函数也能读取到这个值。它们都保持完好无损。

三、区分useState与useRef的使用

使用Hooks,同样的原则也适用于状态。看这个例子:

function MessageThread() {
  const [message, setMessage] = useState('');
  const showMessage = () => {
    alert('You said: ' + message);
  };
  const handleSendClick = () => {
    setTimeout(showMessage, 3000);
  };
  const handleMessageChange = (e) => {
    setMessage(e.target.value);
  };
  return (
    <>
      <input value={message} onChange={handleMessageChange} />
      <button onClick={handleSendClick}>Send</button>
    </>
  );
}

如果我发送一条特定的消息,组件不应该对实际发送的是哪条消息感到困惑。这个函数组件的变量捕获了我们在浏览器中执行单击处理函数的那一次渲染。所以当我点击“发送”时那一刻输入框中的内容就会被设置为弹出的值。

因此我们知道,在默认情况下React中的函数会捕获props和state。但是如果我们想要读取并不属于这一次特定渲染的,最新的props和state呢?

在函数式组件中,你也可以拥有一个在所有的组件渲染帧中共享的可变变量。它被成为“ref”:

function MyComponent() {
  const ref = useRef(null);
  // 你可以通过 ref.current 来获取保存的值.
  // ...
}

在很多情况下,你并不需要它们,并且分配它们将是一种浪费。但是,如果你愿意,你可以这样手动地来追踪这些值:

function MessageThread() {
  const [message, setMessage] = useState('');
  const latestMessage = useRef('');
  const showMessage = () => {
    alert('You said: ' + latestMessage.current);
  };
  const handleSendClick = () => {
    setTimeout(showMessage, 3000);
  };
  const handleMessageChange = (e) => {
    setMessage(e.target.value);
    latestMessage.current = e.target.value;
  };

如果我们在 state 中读取,我们将得到在我们按下发送按钮那一刻的信息。但是当我们通过 ref 读取时,我们将得到最新的值,即使我们在按下发送按钮后继续输入。

通常情况下,你应该避免在渲染期间读取或者设置refs,因为它们是可变得。我们希望保持渲染的可预测性。然而,如果我们想要特定props或者state的最新值,那么手动更新ref会有些烦人。我们可以通过使用一个effect来自动化实现它:

function MessageThread() {
  const [message, setMessage] = useState('');
  // 保持追踪最新的值。
  const latestMessage = useRef('');
  useEffect(() => {
    latestMessage.current = message;
  });
  const showMessage = () => {
    alert('You said: ' + latestMessage.current);
  };

正如我们上面看到的,闭包实际上帮我们解决了很难注意到的细微问题。同样,它们也使得在并发模式下能更轻松地编写能够正确运行的代码。这是可行的,因为组件内部的逻辑在渲染它时捕获并包含了正确的props和state。

React函数总是捕获他们的值 —— 现在我们也知道这是为什么了。

到此这篇关于React函数组件与类的区别有哪些的文章就介绍到这了,更多相关React函数组件与类内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: React函数组件与类的区别有哪些

本文链接: https://lsjlt.com/news/169914.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • React函数组件与类的区别有哪些
    目录一、函数式组件捕获了渲染所用的值二、闭包让类组件成为拥有特定props和state的渲染三、区分useState与useRef的使用首先我们要知道的是,项目性能能主要取决于代码的...
    99+
    2022-11-13
    React函数组件与类 React函数组件
  • react类组件和函数组件区别有哪些
    React 类组件和函数组件是两种不同的组件写法,它们之间有以下几个主要区别:1. 语法:React 类组件是通过 ES6 的 cl...
    99+
    2023-10-07
    react
  • React函数组件和类组件的区别及说明
    目录React函数组件和类组件区别函数组件类组件区别React函数式组件和类组件的优缺点1.类组件的性能消耗比较大2.函数式组件性能消耗小React函数组件和类组件区别 定义组件有两...
    99+
    2022-11-13
    React函数组件 React类组件 React函数
  • react函数组件对比类组件有哪些优势
    这篇文章主要讲解了“react函数组件对比类组件有哪些优势”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“react函数组件对比类组件有哪些优势”吧! ...
    99+
    2024-04-02
  • angular与react的区别有哪些
    这篇文章主要介绍了angular与react的区别有哪些的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇angular与react的区别有哪些文章都会有所收获,下面我们一起来看看...
    99+
    2024-04-02
  • vue与react的区别有哪些
    vue与react的区别:1、vue与react两者监听数据变化的实现原理不同;2、vue能够支持双向绑定,而react不能支持;3、vue组合不同功能的方式是通过mixin,而react则是HoC高阶组件实现;4、在组件通信中子组件向父组...
    99+
    2024-04-02
  • React与Angular有哪些区别
    这篇文章主要介绍“React与Angular有哪些区别”,在日常操作中,相信很多人在React与Angular有哪些区别问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Reac...
    99+
    2024-04-02
  • react受控组件和不受控组件的区别有哪些
    今天小编给大家分享的是react受控组件和不受控组件的区别有哪些,相信很多人都不太了解,为了让大家更加了解,所以给大家总结了以下内容,一起往下看吧。一定会有所收获的哦。 reac...
    99+
    2024-04-02
  • java数组与javascript数组有哪些区别
    本篇内容主要讲解“java数组与javascript数组有哪些区别”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“java数组与javascript数组有哪些区别...
    99+
    2024-04-02
  • 使用React与Vue的区别有哪些
    这篇文章主要介绍“使用React与Vue的区别有哪些”,在日常操作中,相信很多人在使用React与Vue的区别有哪些问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”使用Reac...
    99+
    2024-04-02
  • React函数组件与类组件怎么使用
    这篇“React函数组件与类组件怎么使用”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“React函数组件与类组件怎么使用”文...
    99+
    2023-06-30
  • PHP 函数与 React Native 函数的区别
    PHP 函数与 React Native 函数的区别 简介 PHP 函数和 React Native 函数在语法和使用方式方面存在一些关键区别。本文将探讨这些差异,并通过实际示例来进一...
    99+
    2024-04-24
    php 作用域
  • react native和react的区别有哪些
    这篇文章主要介绍react native和react的区别有哪些,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!区别:1、React是驱动html dom渲染; React Native是驱动android/ios原生...
    99+
    2023-06-06
  • react与vue的虚拟dom有哪些区别
    本篇内容主要讲解“react与vue的虚拟dom有哪些区别”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“react与vue的虚拟dom有哪些区别”吧! ...
    99+
    2024-04-02
  • Angular入口组件与声明式组件的区别有哪些
    小编给大家分享一下Angular入口组件与声明式组件的区别有哪些,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!前言组件是Angu...
    99+
    2024-04-02
  • es6与es5的构造函数有哪些区别
    这篇文章主要介绍“es6与es5的构造函数有哪些区别”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“es6与es5的构造函数有哪些区别”文章能帮助大家解决问题。 ...
    99+
    2024-04-02
  • C++中虚函数与纯虚函数的区别有哪些
    小编给大家分享一下C++中虚函数与纯虚函数的区别有哪些,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!什么是虚函数:虚函数 是在基类中使用关键字 virtual 声...
    99+
    2023-06-20
  • Vue和React的区别有哪些
    今天就跟大家聊聊有关Vue和React的区别有哪些,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。监听数据变化的实现原理不同Vue 通过 getter...
    99+
    2024-04-02
  • react和webpack的区别有哪些
    本文小编为大家详细介绍“react和webpack的区别有哪些”,内容详细,步骤清晰,细节处理妥当,希望这篇“react和webpack的区别有哪些”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起...
    99+
    2024-04-02
  • react和flutter的区别有哪些
    本篇内容介绍了“react和flutter的区别有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成! ...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作