三、react中类组件和函数组件

2023-11-19

简介

本篇我们只要介绍react中类组件与函数组件两种组件的写法、两者的优缺点;

同时对在我们的项目开发中该使用类组件还是函数组件进行思考分析;

废话不多说进入正题~

类组件

设计思路

类组件时面向对象编程的思想,在其中我们去设计类组件时使用state对象去完成组件内部数据的定义,结合react的生命周期构造(componentDidMount、componentDidUpdate、componentWillUnmount等等)完成整个组件的开发设计;

具体实现

示例

import React, {Component} from 'react';

class MyDemo extends Component {
  defaultProps = {
    test: 1,  // 如果没有给组件传test,那么props中test默认为1
  }
  constructor(props) {
    super(props);
    this.state = {
      name: '类组件',
      info: 'demo',
    }
  }
  componentDidMount () {
    console.log('我是一个生命周期函数,在完成首次渲染后调用');
    this.sayHello();
  }
  componentDidUpdate() {
    console.log('我是一个生命周期函数,在完成数据更新并渲染完成后调用')
  }
  componentWillUnmount() {
    console.log('我是一个生命周期函数,在组件销毁前调用');
  }
  sayHello () {
    console.log('hello!我是', this.state);
  }
  changeInfoValue () {
    this.setState({
      info: 'newDemo',
    },() => {
      console.log('state中的info属性值完成更新,变为', this.state.info);
    });
  }

  render() {
    return (
      <div onClick={changeInfoValue}>
        {this.state.name}
      </div>
    )
  }
}
export default MyDemo;

正如上面所示,便完成了我们一个类组件,当然其中还有一些其他的生命周期函数,我们在上一篇已经讲过了,不了解的小伙伴回到上一篇去看看,这里就不再介绍;

函数组件

设计模式

函数组件中没有 this,它提供了hook一系列方法来代替原先 类函数 中的一些特性,例如用useState创建状态变量,使用useEffect实现类似于componmentDidMount、shouldComponentUpdate等生命周期钩子函数的功能。

为啥都有类组件的模式了,还要推出函数组件呢

核心目的:为了降低复杂度、降低学习成本和理解成本;(这里并不是说类组件就不好啊~)

  • class也是有学习成本的,你必须去理解class中this的指向,其没有稳定的法语提案,但是对比而言函数就简单粗暴些了;
  • 要关注很多生命周期的状态这些,组件是一个套着一个,每个小组件中又有各个自己的生命周期,这就让一个复杂的组件有时候变得难以理解(当然这也和开发者自身的组件设计有关),函数组件则没有这些,hook提供的的方法在我看来对一下数据的状态管理更加可预测;

ps:react 并计划说要把类组件从react中移除,在一个项目中类组件和函数组件是可以共存的,facebokk就有一堆的类组件,但是他们并没有把他们全部重写成函数组件,在后续代码中他们会同时去使用 hook 和 class

什么是Hook

Hook是 react 在16.8后新加的特性,它能让我们不通过 class类的方式去写一个组件,也就是用函数的方式去写,它提供一系列的hook方法去代替state、生命周期等react特性;

ps:hook方法不能在类组件中去使用,一定写在函数组件的最外层,注意是最外层!!!

函数组件中有哪些Hook呢

useState

import { useState } from 'react';
const [state, setState] = useState(initialState);

返回一个 state,以及更新 state 的函数。

在初始渲染期间,返回的状态 (state) 与传入的第一个参数 (initialState) 值相同。

setState 函数用于更新 state。它接收一个新的 state 值并将组件的一次重新渲染加入队列。

注意:如果你的更新值与当前 state 完全相同(React 使用 Object.is比较算法 来比较 state),则随后的重渲染会被完全跳过。

useEffect

import { useEffect } from 'react';
useEffect(() => {
  const subscription = props.source.subscribe();
  return () => {
    // 清除订阅
    subscription.unsubscribe();
  };
}, []);

在了解useEffect时你要知道几个概念:如何清除effect、effect的执行时机、如何控制effect的执行条件

  • 清除effect:在传入函数中的 return中加入一个函数,则这个函数就会在当组件卸载前执行;
  • effect的执行时机:执行时机与 componentDidMount、componentDidUpdate 不同的是,传给 useEffect 的函数会在浏览器完成布局与绘制之后,在一个延迟事件中被调用。
  • 增加effect的执行条件:可以给 useEffect 传递第二个参数,它是 effect 所依赖的值数组

注意

如果想执行只运行一次的 effect(仅在组件挂载和卸载时执行),可以传递一个空数组([])作为第二个参数。这就告诉 React 你的 effect 不依赖于 props 或 state 中的任何值,所以它永远都不需要重复执行。这并不属于特殊情况 —— 它依然遵循输入数组的工作方式。

useContext

之前我们有讲过父子组件间传值的一种方式

先通过React.createContext()方式创建一个context,然后在函数内通过useContext()的方式返回context的当前值

const themes = {
  light: {
    foreground: "#000000",
    background: "#eeeeee"
  },
  dark: {
    foreground: "#ffffff",
    background: "#222222"
  }
};

const ThemeContext = React.createContext(themes.light);

function App() {
  return (
    <ThemeContext.Provider value={themes.dark}>
      <Toolbar />
    </ThemeContext.Provider>
  );
}

function Toolbar(props) {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

function ThemedButton() {
  const theme = useContext(ThemeContext);
  return (
    <button style={{ background: theme.background, color: theme.foreground }}>
      I am styled by theme context!
    </button>
  );
}

useReducer

当一个state有多个可以改变其的方法,或者说依赖了很多的其他state时,用useState显然通过setState去改state时需要用到很多的方法,写法繁杂,此时就可以用useReducer去代替它

useReduceruseState的平替方法

示例

const demo = () => {
  const initState = {count: 0};
  const reduce = (state, action) => {
    switch (action.type) {
    case 'increment':
      return {count: state.count + 1};
    case 'decrement':
      return {count: state.count - 1};
    case 'reset':
      return init(action.payload);
    default:
      throw new Error();
  }
  const [state, dispatch] = useReducer(reduce, initState);
    
  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({type: 'reset', payload: initState})}>
        Reset
      </button>
      <button onClick={() => dispatch({type: 'decrement'})}>-</button>
      <button onClick={() => dispatch({type: 'increment'})}>+</button>
    </>
  );
}

ps:一般创建用到它比较少,但是如果我们用上它结合useContext就可以模拟实现redux的行为

useMemo

useMemo是用来缓存计算属性的;

计算属性其实是函数的返回值,或者说指那些以返回一个值为目标的函数。

有些函数,需要我们手动的去点击,去完成一些动作才触发。而有些函数,则是直接在渲染的时候就执行,在DOM区域被当作属性值一样去使用,这些就被称为计算属性。

有时候我们直接在dom中加入计算属性,那么每次渲染时它都会执行得到一个值,但是这个值明明每次执行得结果都一样,没必要每次都执行呀,这时候我们就可以用上useMemo,和vue中computer中定义方法差不多

const demo = () => {
  const [count, setCount] = useState(0);
  const doubleCount = useMemo(() => {
    return count*2;
  },[count])

  const newCount = useMemo(() => {
    let currentCount = 0
    for(let i=0;i<100000;++i){
      currentCount = currentCount + i + count;
    }
    return currentCount;
  },[count])
  return (
    <div>
      {doubleCount}
      {newCount}
    </div>
  )
}

ps:useMemo不是越多越好哈,缓存也是需要成本的,那我们时候需要优化呢?但计算量很大很复杂时用更合适,不要滥用,像上面例子中doubleCount没必要了用useMemonewCount就可以用useMemo

useCallback

它和useMemo的功能都做缓存用,只不过useCallback缓存的时函数,useMemo缓存的计算属性也就是值

const memoizedCallback = useCallback(
  () => {
    doSomething(a, b);
  },
  [a, b],
);

ps:一样不能滥用,使用场景很少吧(个人理解)

useRef

一般我们在react组件中获取Dom有两个方法,一个是用传统的document,另外一个就是用useRef方法

const demoDom = () => {
  const input = useRef(null);
  const inputEl = useRef(null);
  const onButtonClick = () => {
    //这里的inputEl.current和document.getElementById('myInput')一样
    inputEl.current.focus();
  };
  return (
    <>
      <input ref={inputEl} id="myInput" type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}

除了上面的hook,react还提供了useImperativeHandleuseLayoutEffectuseDebugValue这些hook方法,这里就不展开说了,可以去react官网看看

通过react提供的上面这些hook方法,我们就能模拟类函数中的生命周期函数,用函数的设计模式去写组件

总结

类组件和函数组件共同点

  • 无论是使用函数组件还是类组件,它都不能修改自己的 props 属性。
  • React是单向数据流,父组件改变了属性,那么子组件视图会更新。
  • 函数组件和类组件都可以接收 props 属性并且返回React元素。
  • 属性 props 是外界传递过来的,状态 state 是组件本身的,状态可以在组件中任意修改。

类组件和函数组件区别

当然函数组件和类组件是有区别的,而且函数组件比类组件性能好,因为类组件使用的时候要实例化,而函数组件直接执行函数取返回结果即可。为了提高性能,尽量使用函数组件(多写无状态组件,少写有状态组件)。

区别

类组件

函数组件

是否有this

没有

是否有生命周期

没有

是否有状态state

没有

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

三、react中类组件和函数组件 的相关文章

  • 以编程方式填写reactjs表单

    我正在编写一个用户脚本 但无法填写由reactjs制作的表单 我的代码 document querySelector id username value email protected cdn cgi l email protection
  • 使用 dc.js 按条形值对条形图中的条形进行排序(排序)

    如何通过维度的计算值而不是维度本身的名称对 dc js 示例中的 x 轴 维度 进行排序 例如 请考虑序数条形图的 dc js 示例 https github com dc js dc js blob master web examples
  • Snap.svg - 停止在可悬停元素的子元素上重新触发悬停事件

    对于一个项目 我使用的 SVG 形状由背景多边形和背景多边形上方的一些文本 我已将其转换为路径 组成 我正在使用 Snap svg 为我的形状设置动画 当我将鼠标悬停在多边形上时 形状应该缩放到特定尺寸 包括其中的所有内容 鼠标移开时 形状
  • 在打字稿中导入 json

    我是 typescript 的新手 在我的项目中 我们使用 typescript2 在我的要求之一中 我需要导入 json 文件 所以我创建了 d ts 文件如下 test d ts declare module json const va
  • 隐藏 Div 的父级

    我只是想隐藏父divcomments section div class content content green div div div 我试过这个 document getElementById comments section pa
  • 设置 cookie 时中断 JavaScript 执行

    当设置 cookie 时 是否可以始终中断浏览器开发人员工具中的 javascript 执行 无需显式设置 JS 断点 document cookie 在 html head 块的开头添加此代码片段效果很好
  • 如何解决 Typescript 构建中的错误“找不到模块 'jquery'”

    我目前在 ts 文件的顶部有这个import require jquery 我这样做是因为我试图在我的打字稿文件中使用 jquery 但我似乎无法编译它 因为它返回标题中所述的错误 我正在使用 ASP NET CORE 脚本文件夹 tsco
  • 将 UMD Javascript 模块导入浏览器

    你好 我正在对 RxJS 进行一些研究 我可以通过在浏览器中引用它来使用该库 如下所示 它使用全局对象命名空间变量 Rx 导入 我可以制作可观察的东西并做所有有趣的事情 当我将 src 更改为指向最新的 UMD 文件时 一切都会崩溃 如下所
  • 页面上使用 HTML Editor Extender 进行回发会导致 IE11 中出现 JavaScript 错误

    我已将 HTML 编辑器扩展程序添加到我正在处理的页面中 现在每当我在页面上发回帖子时 都会收到以下 Javascript 错误 JavaScript 运行时错误 参数无效 之后什么也没有发生 这在 IE10 或更低版本以及我所知道的所有其
  • 在 ReactJS 中创建动态目录

    我有一个组件 它代表一个页面 其中有多个SectionHeader 组件作为该页面的子组件 我想通过检查 Page 的子项 SectionHeaders 来动态创建目录
  • 从数据库检查数据的异步解决方案各种循环子句

    我想要做的是异步检查数据库并从中获取结果 在我的应用程序中我试图实现Asynchronously将此步骤解决为 从数据库中检查手机号码JsonArray循环子句的种类 Create JsonArray从结果 打印创建的数组 我学到了足够多的
  • Vue 和 Vuex:处理依赖的计算属性

    我的应用程序是一个使用 Vuex 在 Vue 中构建的精简电子表格 关键组件是TableCollection Table and Row The TableCollection有一个包含多个的数组Table对象 每个Table有一个包含多个
  • 如何使用 crypto-js 解密 AES ECB

    我正在尝试将加密数据从 flash 客户端 发送到服务器端的 javascript 在 asp 中作为 jscript 运行 有几个 javascript Aes 库 但它们实际上没有文档记录 我正在尝试使用 crypto js 但无法让代
  • 在 Javascript 中连接空数组

    我正在浏览一些代码 我想知道这有什么用处 grid push concat row 根据我的理解 它等同于 grid push row 为什么要大惊小怪 连接 你想使用 concat当您需要展平数组并且没有由其他数组组成的数组时 例如 va
  • 在 Shopify 商店中嵌入 Vue 组件

    在产品页面中 我尝试显示自定义 Vue 组件 为简洁起见 该组件根据给定的产品 ID 显示 Firebase 数据库中的一些信息 我最初尝试将其制作为 Shopify 应用程序 以便我可以访问他们的 API 我实现了 OAuth 并且可以检
  • 从 FileReader 设置背景图像样式

    我正在寻找一种解决方案 允许我从文件上传输入中获取文件并通过设置 document body style backgroundImage 来预览它 以下代码用于在 Image 元素中显示预览 function setImage id tar
  • 在 CKEditor 中设置字体大小和字体系列

    我正在使用 ckeditor 我想问一下这个插件如何设置font family和font size 我尝试过使用 CKEDITOR config font defaultLabel Arial CKEDITOR config fontSiz
  • 使用 MongoDB 和 Nodejs 插入和查询日期

    我需要一些帮助在 mongodb 和 nodejs 中按日期查找记录 我将日期添加到抓取脚本中的 json 对象 如下所示 jsonObj last updated new Date 该对象被插入到 mongodb 中 我可以看到如下 la
  • 如何在执行新操作时取消先前操作的执行?

    我有一个动作创建器 它会进行昂贵的计算 并在每次用户输入内容时调度一个动作 基本上是实时更新 但是 如果用户输入多个内容 我不希望之前昂贵的计算完全运行 理想情况下 我希望能够取消执行先前的计算并只执行当前的计算 没有内置功能可以取消Pro
  • 如何在react-highcharts中使用图表工具提示格式化程序?

    如何使用图表工具提示格式化程序 我正在使用高图表的反应包装器 我有这样的配置 const CHART CONFIG tooltip formatter tooltip gt var s b this x b each this points

随机推荐

  • 华为OD机试真题- 任务混部

    题目描述 公司创新实验室正在研究如何最小化资源成本 最大化资源利用率 请你设计算法帮他们解决一个任务混部问题 有taskNum项任务 每个任务有开始时间 startTime 结束时间 endTime 并行度 parallelism 三个属性
  • LeetCode 剑指 Offer II 079. 所有子集

    给定一个整数数组 nums 数组中的元素 互不相同 返回该数组所有可能的子集 幂集 解集 不能 包含重复的子集 你可以按 任意顺序 返回解集 示例 1 输入 nums 1 2 3 输出 1 2 1 2 3 1 3 2 3 1 2 3 1 l
  • libgdx导入blender模型

    具体就是参考 官网 https libgdx com wiki graphics 3d importing blender models in libgdx blender 教程可以看八个案例教程带你从0到1入门blender 已完结 这里
  • 小米盒子打开adb调试模式

    1 先打开开发者模式 进入小米电视设置 gt 进入关于 gt 找到产品型号 gt 在产品型号上面连续多次按ok 确认 键 gt 然后就会提示 您已处于开发者模式 2 开启adb 经过第一步开启开发者模式之后 现在可以返回到设置页面 进入 账
  • stl库

    sort 读入n条学生成绩记录 包括学生姓名 总成绩 语文 数学和英语成绩 要求按总成绩从高到低输出 条记录 每条记录占一行 总成绩相同时按语文成绩从高到低输出 语文成绩相同时按数学成绩从高到低输出 没有两个人的成绩完全一样 include
  • 【JAVA】Abnormal build process termination: -Xmx700m -Djava.awt.headless=true -Djava.endorsed.d如何解决???

    Abnormal build process termination Xmx700m Djava awt headless true Djava endorsed dirs Djdt compiler u 如何解决 在尝试了n中网络上的方法
  • Vue中上传图片

    上传图片的两种方式 1 base64 上传 将图片转换成base64 然后再通过请求将base64上传到服务端 图片转换成base64很简单 直接百度就可以了 一大堆图片转base64的插件 但转换成的base64特别长 一般不建议使用 2
  • onnxruntime cuda版本使用时出现的错误汇总

    1 用qt c 推理 onnxruntime cuda时出现诸如 E onnxruntime barcode provider bridge ort cc 995 onnxruntime ProviderLibrary Get LoadLi
  • 程杰“大话设计模式”中的设计原则

    单一职责原则 SRP 就一个类而言 应该仅有一个引起它变化的原因 如果一个类承担的职责过多 就等于把这些职责耦合在了一起 一个职责的变化可能会削弱或者抑制这个类完成其他职责的能力 这种耦合会导致脆弱的设计 当发生变化时 设计会遭受到意想不到
  • Python爬虫中如何通过post发请求,浏览器控制台抓包教程,有道翻译爬虫程序,通过python伪装翻译(post案例)

    目录 一 浏览器控制台抓包 1 打开方式以及常用选项 2 控制台NetWrok 二 Python爬虫中如何通过post发请求 1 Post请求 2 Python中使用post请求 三 有道翻译爬虫程序 通过python伪装翻译 post案例
  • Eclipse出现A project with this name already exists问题

    问题如图 我是由于删除时并没有删除完全造成的 解决 出现这种情况有可能是由于project命名冲突 但是可能自己并没发现有冲突的命名 有可能是以前命名过 但是没有完全删除以至于发生了冲突 可以在下图中的Navigator中查看是否已有此pr
  • 虚拟机上ubuntu-server的安装(详细完整版)

    一 安装 安装VMware 网上找Ubuntu的iso文件 桌面版的或者服务器版的都可以 Index of ubuntu releases 清华大学开源软件镜像站 Tsinghua Open Source Mirrorhttps mirro
  • 软件项目管理

    目录 前言 项目管理概述 项目与软件项目 项目管理与软件项目管理 项目管理知识体系 过程管理与软件项目管理的关系 软件项目管理过程 项目初始 项目确立 项目立项 项目招投标 项目授权 敏捷开发总结 scrum模型 迭代式增量软件开发过程 术
  • Apple:如何在iphone、ipad上安装一些常用命令行命令

    Apple 如何在iphone ipad上安装一些常用命令行命令 相信对Linux Unix比较熟悉的朋友 在iphone或 ipad越狱后发现通过Cydia可以安装OpenSSH 一定都想安装上并且通过ssh登录上去看看 但是登录后却发现
  • 推荐一些网络安全的网站和论坛

    今天小编给大家推荐一批网络安全的网站和论坛 想学习网络安全技术的朋友们可以去这些网站看看 1 红黑联盟 红黑联盟论坛 网址 bbs 2cto com 2 安全客 一个提供网络安全资讯的网站 网址 www anquanke com 3 T00
  • 【批处理DOS-CMD命令-汇总和小结】-CMD窗口的设置与操作命令-关闭cmd窗口、退出cmd环境(exit、exit /b、goto :eof)

    一 对exit命令和goto命令的基本认知 打印exit命令的帮助信息 执行命令 exit C Users Administrator gt exit 退出 CMD EXE 程序 命令解释器 或当前批处理脚本 EXIT B exitCode
  • php文件打印服务器,PHP打印到服务器端打印机

    我想用PHP打印到服务器端打印机 我发现了类似的示例代码 它们大多都使用相同的API函数来执行此任务 当我在我的服务器上运行它来测试它所说的代码时 PHP致命错误 调用未定义的函数printer open 所以我发现至少有三种不同版本的ph
  • keras.layers.Conv2D 与tf.layers.Conv2D 的兼容性: AttributeError: ‘tuple‘ object has no attribute ‘layer‘

    结论 keras layers Conv2D 与 tf layers Conv2D有相同的参数设置模式 keras layers Conv2D 可以兼容处理 tf layers Conv2D得到的tensor tf layers Conv2
  • 表示数值的字符串(含思路解答示意图)【剑指offer——JAVA实现】

    题目描述 请实现一个函数用来判断字符串是否表示数值 包括整数和小数 例如 字符串 100 5e2 123 3 1416 和 1E 16 都表示数值 但是 12e 1a3 14 1 2 3 5 和 12e 4 3 都不是 解法一 思路 状态机
  • 三、react中类组件和函数组件

    简介 本篇我们只要介绍react中类组件与函数组件两种组件的写法 两者的优缺点 同时对在我们的项目开发中该使用类组件还是函数组件进行思考分析 废话不多说进入正题 类组件 设计思路 类组件时面向对象编程的思想 在其中我们去设计类组件时使用st