【react全家桶学习】react中函数组件和类式组件(超详/必看)

news2024/10/5 13:35:51

函数式组件定义及特点

定义(核心就是一个函数,返回虚拟dom):

import React from 'react'

export default function index() {
  return <div>index</div>
}

特点:

  • 1、适用于【简单组件】的定义
  • 2、是一个函数,返回虚拟dom
  • 3、函数名就是组件名

类式组件的定义及特点

学习之前可以先复习一下类相关的知识:

ES6--class类(详解/看完必会)_class es6_suoh's Blog的博客-CSDN博客

或者通过下面代码复习要用到的类的知识点(认真看、有帮助):

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
</head>

<body>
	<script>
		/**
		 * 总结:
		 * 1、类中的构造器不是必须写的,要对实例进行一些初始化的操作,如添加指定属性时才写
		 * 2、如果A类继承了B类,且A类中写了构造器,那么A类构造器中的super是必须要调用的
		 * 3、类中所定义的方法,都是放在了类的原型对象上,供实例使用
		 */
		// 创建一个Person类
		class Person {
			// 构造器方法,接收参数
			constructor(name, age) {
				// 构造器中的this是谁?---是类的实例对象(p1/p2)
				this.name = name
				this.age = age
			}
			// 一般方法
			speak() {
				// speak方法放在了哪里?--Person的原型对象上,供实例使用
				// 通过Person实例(p1/p2)调用speak时,speak中的this就是Person实例
				console.log(`我的名字是${this.name},我的年龄是${this.age}~`)
			}
		}
		// 创建一个Person的实例对象
		const p1 = new Person("小锁", 19)
		const p2 = new Person("小索", 20)
		p1.speak() //实例p1调用Person类原型链上的方法speak
		p2.speak() //实例p2调用Person类原型链上的方法speak
		p1.speak.call({
			a: 1,
			b: 2
		}) //使用call调用改变this指向,传的是谁,this就指向谁
		// 创建一个Student类,继承于Person类
		class Student extends Person {
			// 这里不需要接收s1传过来的姓名和年龄参数,因为我们继承了Person,
			// Person里面接收了这两个参数,下面我们只需要接收年级就好了
			constructor(name, age, grade) {
				// 下面写法不可取,因为属性多的时候,会和父类的赋值重复非常冗余
				// 	this.name = name
				// 	this.age = age
				// 因此我们利用super关键字,帮助我们在子类中调用父类
				// 将父类接收的2个参数传递过去即可
				// 注意:super关键字必须写在最前面,不能处于this.grade = grade之后
				super(name, age)
				this.grade = grade
			}
			// 重写从父类继承过来的方法
			speak() {
				console.log(`我的名字是${this.name},我的年龄是${this.age},我的年级是${this.grade}~`)
			}
			// 一般方法
			study() {
				// study方法放在了哪里?--类的原型对象上,供实例使用
				// 通过Student实例s1调用speak时,speak中的this就是Student实例
				console.log(`我的名字是${this.name},我的年龄是${this.age}~`)
			}
		}
		const s1 = new Student('小美', 19, '大学')
		console.log(s1)
		// 如果自身不存在学生也能访问到父类的speak方法,原型链的原因
		s1.speak()
	</script>
</body>

</html>l

特点:

  • 1、适用于【复杂组件】的定义
  • 2、组件是用类定义的,随后new出来该类的实例,并通过该实例调用到原型上的render方法
  • 3、将render返回的虚拟dom转为真实dom,呈现在页面中

定义方式:

import React, { Component } from 'react'
// 创建类式组件
export default class index extends Component {
  // render是放在哪里的?--在index组件的原型对象上,供实例使用
  // render的this是谁?--在index组件的实例对象(index组件实例对象)
  render() {
    console.log(this)
    return <div>index</div>
  }
}

我们打印一下this,输出的是组件的实例对象。

补充1:什么是复杂组件?

复杂组件:就是有状态(state)的组件就叫复杂组件 

除了使用外部数据 (通过 this.props 访问)以外,组件还可以维护其内部的状态数据 (通过 this.state 访问)。当组件的状态数据改变时,组件会再次调用 render() 方法重新染对应的标记。 

补充2:什么是 state(状态)?

  • state 是组件对象最重要的属性,值是对象(可以包含多个 key-value 的组合)
  • 组件被称为"状态机"通过更新组件的 state 来更新对应的页面显示(重新染组件)
  • react 里,只需更新组件的 state,然后根据新的 state 重新渲染用户界面(不要操作 DOM)。

state中的值可以修改,修改的唯一方法是调用 this.setState(后面会讲) ,每次修改以后,自动调用 this.render 方法,再次渲染组件。

(也就是说直接this.state.num = 2这样直接修改值是无效的)
state在组件的构造函数中赋值 

举个例子,让页面根据state中的值来进行变化。

假如我们想给state里面放入一个week参数,注意:state 的值是对象(可以包含多个 key-value 的组合),步骤如下

 可以看到,传入成功

 读取state的值,直接this.state.xxx即可

也可以利用解构赋值简化代码

  

  

 那我们想要通过点击事件动态改变这个属性如何处理?下面来讲react中的事件绑定

补充3:react中的事件绑定

react中的事件绑定呢,跟原生js及其相似,只不过在原生的基础上添加了一点点区别、

例如事件命名方式:原生onclick -->react是onClick 、原生onblur -->react是onBlur等。

  • React事件的命名采用的是小驼峰式, 例如(onClick),而不是纯小写(onclick)
  • 使用JSX语法的时候,需要传入一个函数作为事件处理函数,而不是一个字符串

试一下:

页面报错了,看来用个字符串确实不行, 

 翻译过来,说是onClick必须是个函数而不是字符串

 好吧。挺多事的、看来得用花括号包裹,才能保证他是一个函数

法一:点击事件写在render里面

 注意:如果在标签的函数里面直接添加了小括号,那么他就会一上来就开始调用。

因此需要把小括号去掉,这样就完美了~

 这时有人可能会发现,我上面函数 testFunc的定义 是位于render里面。

法二:当然还有一种写法,就是将函数写在外面(推荐),两者的区别往下看

补充4:react事件函数写在render里外的区别 

 React的事件函数可以写在render里外,但是它们的区别在于:

  • 1、写在render里的事件函数可以跟随渲染周期每次重新实例化,这样可以保证它们的最新状态;而写在render外的事件函数只在第一次加载时被实例化,不能保证最新状态。
  • 2、写在render里的事件函数可以被重新实例化,可以保证它们具有最新的props和state;而写在render外的事件函数只能获取它们在第一次加载时的props和state,不能保证最新的props和state。
  • 3、写在render里的事件函数可以和render的内容组合在一起,可以实现更好的可读性和维护性;而写在render外的事件函数可以使代码结构更加清晰,可以使代码更易读。
  • 4、写在render里的事件函数需要加上function,且调用时需要加上this;写在render外的事件函数不需要加function,调用时也不需要加this
  • 5、由于在render里调用this.setState事件会陷入死循环(原因是参考博主:react 中千万不要在render里调用this.setState_render里面写setstate_小刘先生很努力的博客-CSDN博客。因此我们在大部分场景中还是推荐写在render外

总之,写在render里和写在render外的事件函数各有优缺点,在使用时要根据实际情况来选择。

问题来了,现在我们已经可以实现点击事件了,那我想在点击的时候改变state中的week值,如何写?有人说直接赋值就好了呀

 看下效果:当我点击的一下之后报错了,说state未定义,这说明通过this没找到state呀。

大胆推测:this指向出现了问题。

补充5:如何修改类中方法的this指向

 那构造器的this以及render中的this均指向index组件实例,怎么就函数的this出现了undefined?

(1)因为类中定义的方法已经在局部开启了严格模式

(2)只有通过实例调用的才会正常,而testFunc是作为onClick的回调,所以不是通过实例调用的,是直接调用,所以this指向为undefined

所以接下来我们只能改变this指向来让他指向index组件实例,如何解决?

改变this指向的方法有apply call 箭头函数 bind,都试下

call和apply都试了下,都是一上来就执行,所以不可行

 

 注意:bind是返回对应函数,便于稍后调用;apply、call则是立即调用 。

            还有箭头函数,文章后面代码精简的时候会讲解到

因此我们得用bind

重点是这一句:this.testFunc = this.testFunc.bind(this) 代表的含义就是,将原型上的testFunc函数通过bind改变this指向(使其指向index组件实例)返回一个新的函数重新赋值给testFunc函数,这样testFunc函数的this指向就正常了、

 此时就打印出正常的this信息了、

 

 补充6:解决了this指向,如何通过this去改变state中数据的值?

解决了this指向,我们重新在方法中访问state值就不会报错了。

 

state值修改成功了?可页面怎么没变???

注意:不可以直接对state中的数据直接进行修改(this.state.week = '周二' 【错误写法】)。要借助内置API【setState】进行修改

这样就正常了、 

 

补充7:contructor调用几次?render调用几次?

: contructor只调用一次,render会调用1+n次 (1是初始化的那次,n是状态更新的次数)

小总结:

1、构造器的作用

  • 初始化状态
  • 解决类方法的this指向问题

2、render的作用

  • 从状态state里面读取数据
  • 根据状态进行页面展示

代码简化一:

在上面的关于类的复习里面已经讲了,构造器的作用主要是用于接收外部传进来的参数,当我们不需要接收外部传进来的值时是可以不用构造器的。而且需要注意:类中是可以直接写赋值语句的,但不能随意写代码,类始终不是函数体,函数体中可以定义变量、打印等,类中不允许

因此我们可以把构造器中的state赋值语句放入类中 ,代表给实例对象index追加了一个属性state

代码简化二: 

当函数特别多的时候,我们可能会再构造器中写多个改变this指向的语句,十分冗余

 改变this指向的方法还有一个是箭头函数、、、、

 这样构造器就可以删了,简化之后

import React, { Component } from 'react'
// 创建类式组件
export default class index extends Component {
  // 初始化状态
  state = {
    week: '周一',
  }
  render() {
    const { week } = this.state
    return <h2 onClick={this.testFunc}>今天才{week}!</h2>
  }
  // 自定义方法--要用赋值语句的形式+箭头函数
  testFunc = () => {
    this.setState({
      week: '周二',
    })
  }
}

终于结束了,这是一个更改react组件页面上的数据引发的一系列问题讲解。希望大家可以认真阅读,绝对有帮助~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/462580.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

macOS与Ubuntu困惑解答

homebrew&#xff08;报管理器&#xff09;、yaml、apt-get、apt是包管理工具&#xff1b; zsh、bash都是解释器&#xff0c;是shell语言的解释器&#xff0c;都是服务于shell语言的&#xff0c;它们之间的区别是&#xff0c;zsh能够很好的兼容bash&#xff0c;zsh更优雅&…

web端导航菜单系列

导航菜单属于导航中最常规的一种导航模式&#xff0c;它有2个显而易见的用途&#xff1a;帮助我们找到想要的任何东西和告诉我们现在身在何处。帮助用户在不同页面之间跳转找到目标功能。 导航作为网站或者平台的骨架&#xff0c;是产品设计中不容忽视的一环。结合自身对于导航…

java第一课

常用dos命令 第一个e&#xff1a;加上回车&#xff0c;直接切换到e盘目录 看e盘文件的文件夹 dir加回车 进入文件夹 cd 文件夹名称加回车 进入文件夹就是 cd加文件夹名称 cd 加一个文件夹的名称就是进入这个文件夹 回退就是cd.. (这样子是单级目录的回退) 进入很多个就是进入…

必备装机软件,软件推荐

https://www.den4b.com/download/renamer/installer?key9d97aa7096681c8342442f75e34f7d5a8b13551ee3283956323516c81b1fe91b 官网https://www.den4b.com/ 从不同的文件夹中选择文件并将它们添加到工作区域。 a、 更改添加文件夹按钮的默认行为(可选步骤) b、添加单独选择的文…

数据库基础篇 《14.视图》

数据库基础篇 《14.视图》 1. 常见的数据库对象 对象描述表(TABLE)表是存储数据的逻辑单元&#xff0c;以行和列的形式存在&#xff0c;列就是字段&#xff0c;行就是记录数据字典就是系统表&#xff0c;存放数据库相关信息的表。系统表的数据通常由数据库系统维护&#xff0…

Ubuntu运行.sh文件

一、运行.sh文件 &#xff08;1&#xff09;使用sh testsh执行 &#xff08;2&#xff09;使用bash testsh 执行 &#xff08;3&#xff09;使用点 执行 &#xff08;4&#xff09;使用source执行./sh 文件开头***的含义&#xff1a; #!/bin/sh     以下的代码由/…

Redis 的 Protected Mode 解读

官方配置文件自带的注释&#xff1a; Protected mode is a layer of security protection, in order to avoid that Redis instances left open on the internet are accessed and exploited.When protected mode is on and if:1) The server is not binding explicitly to a …

服务(第十四篇)lvs的高可用负载均衡

Keepalived 是一个基于VRRP协议来实现的LVS服务高可用方案&#xff0c;可以解决静态路由出现的单点故障问题。 在一个LVS服务集群中通常有主服务器&#xff08;MASTER&#xff09;和备份服务器&#xff08;BACKUP&#xff09;两种角色的服务器&#xff0c;但是对外表现为一个虚…

Qt连接MySql数据库(本地和远程数据库均可)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 三种方法方法一 略方法二 使用ODBC设置mysql为数据源库1. 添加ODBC数据源&#xff0c;在控制面板中找到管理工具&#xff0c;其中有ODBC数据源 64位的&#xff0c;打…

美颜sdk与人脸识别技术的结合:为智能化时代注入美感

在当今的智能化时代&#xff0c;人脸识别技术已经成为了很多应用的核心。而在这些应用中&#xff0c;美颜功能也逐渐成为了用户所追求的重要特性之一。因此&#xff0c;美颜sdk的出现和发展&#xff0c;为人脸识别技术注入了更多的美感。 一、定义和作用 美颜sdk可以对人脸进…

Django框架之模板基本使用

本篇文章主要讲解Django 3.0框架配置模板路径&#xff0c;并使用视图和模板结合实现一些小功能。 概述 模板是html页面&#xff0c;可以根据视图中传递过来的数据进行填充。 在project中创建templates目录和应用模板目录 如templates/myapp 配置模板路径 修改settings.py文…

四数相加 II

给你四个整数数组 nums1、nums2、nums3 和 nums4 &#xff0c;数组长度都是 n &#xff0c;请你计算有多少个元组 (i, j, k, l) 能满足&#xff1a; 0 < i, j, k, l < n nums1[i] nums2[j] nums3[k] nums4[l] 0 来源&#xff1a;力扣&#xff08;LeetCode&#xff0…

Java 网络IO编程总结 nio netty原理 bio nio aio io多路复用 事件驱动 信号驱动 汇总总结

目录 ​编辑 io 多路复用 NIO 多线程 和 io多路复用区别 &#xff1a; Netty 操作流程 看了众多精简总结 Netty Bio Nio Aio Io多路复用 事件驱动 信号驱动 io 多路复用 I/O 多路复用模型是利用select、poll、epoll可以同时监察多个流的 I/O 事件的能力&#xff…

【备忘录设计模式详解】C/Java/JS/Go/Python/TS不同语言实现

简介 备忘录模式&#xff08;Memento Pattern&#xff09;是一种结构型设计模式。这种模式就是在不破坏封装的条件下&#xff0c;将一个对象的状态捕捉(Capture)住&#xff0c;并放在外部存储起来&#xff0c;从而可以在将来合适的时候把这个对象还原到存储起来的状态。备忘录…

接口冒烟测试方法

接口冒烟测试方法 今年遇到了几个问题&#xff0c;与接口的功能和性能相关&#xff0c;恰巧最近公司也在组织以冒烟测试为主题的活动&#xff0c;于是乎突发奇想&#xff0c;寻思着能否将接口测试与冒烟测试结合起来&#xff0c;发掘一些新的接口测试思路与方法。 平时对接口…

SpringBoot创建与运行

文章目录 一、SpringBoot是什么&#xff1f;二、SpringBoot项目创建IDEA创建SpringBoot项目网页版创建SpringBoot项目项目目录介绍输出Hello SpringBoot 一、SpringBoot是什么&#xff1f; 如果我们说Spring的诞生是为了简化Java程序开发的&#xff0c;那么SpringBoot的诞生是为…

【三十天精通Vue 3】 第十八天 Vue 3的国际化详解

✅创作者&#xff1a;陈书予 &#x1f389;个人主页&#xff1a;陈书予的个人主页 &#x1f341;陈书予的个人社区&#xff0c;欢迎你的加入: 陈书予的社区 &#x1f31f;专栏地址: 三十天精通 Vue 3 文章目录 引言一、Vue 3 国际化概述1.1 国际化的概念1.2 国际化的作用1.3 V…

数据结构(数组、链表、栈、队列、树)

文章目录 1.数组1.1数组的特点1.2自定义数组 2.链表2.1链表的特点2.2自定义链表2.2.1自定义单向链表2.2.2自定义双向链表 3.栈3.1栈的特点3.2 Stack使用举例3.3 自定义栈 4. 队列5. 树与二叉树5.1 树的理解5.2 二叉树的基本概念5.3 二叉树的遍历5.4 经典二叉树和红黑树5.5 二叉…

Jmeter基础之---jmeter基础概念

JMeter 介绍&#xff1a; 一个非常优秀的开源的性能测试工具。 优点&#xff1a;你用着用着就会发现它的重多优点&#xff0c;当然不足点也会呈现出来。 从性能工具的原理划分&#xff1a; Jmeter工具和其他性能工具在原理上完全一致&#xff0c;工具包含4个部分&#xff1a…

GitLab与jekins结合构建持续集成(cl)环境(3)

目录 在jenkins上部署maven 配置maven jenkins回滚 Git方式回滚 通过发布时备份&#xff0c;回滚是选择指定备份文件进行回滚 jenkins添加邮件报警 Jenkins如何远程管理部署节点 Jenkins的远程管理方式&#xff1a; SSH Plugin Publish over SSH jenkins整合Ansible je…