React之组件的分类、使用,事件对象,this指向问题,修改状态以及受控组件与非受控组件

React之组件的介绍、创建与使用,事件对象,this指向问题,修改状态以及受控组件与非受控组件

  • 一、组件基本介绍
  • 二、组件创建
    • 2.1 函数组件
    • 2.2 类组件
  • 三、将组件提取到单独的js文件中
  • 四、有状态组件和无状态组件
  • 五、类组件的状态
  • 六、事件处理
    • 6.1 注册事件
    • 6.2 事件对象
    • 6.3 this指向问题
    • 6.4 this指向解决方案
  • 七、setState 修改状态
  • 八、react核心理念(状态不可变)
  • 九、表单处理
    • 9.1 受控组件
    • 9.2 非受控组件-ref

一、组件基本介绍

  • 组件是 React 开发(现代前端开发)中最重要的内容
  • 组件允许你将 UI 拆分为独立、可复用的部分,每个部分都可以独立的思考
  • 组合多个组件(组装乐高积木)实现完整的页面功能
  • 特点:独立、可复用、可组合
  • 组件包含三部分:HTML/CSS/JS
  • 展示页面中的可复用部分

二、组件创建

2.1 函数组件

  • 函数组件:使用JS的函数或者箭头函数创建的组件
    • 使用 JS 的函数(或箭头函数)创建的组件,叫做函数组件
    • 约定1:函数名称必须以大写字母开头,React 据此区分组件和普通的 HTML标签
    • 约定2:函数组件必须有返回值,表示该组件的 UI 结构;如果不需要渲染任何内容,则返回 null
  • 使用函数创建组件
// 使用普通函数创建组件:
function Hello() {return <div>这是我的第一个函数组件!</div>
}
function Button() {return <button>按钮</button>
}// 使用箭头函数创建组件:
const Hello = () => <div>这是我的第一个函数组件!</div>
  • 使用组件
    • 组件就像 HTML 标签一样可以被渲染到页面中。组件表示的是一段结构内容,对于函数组件来说,渲染的内容是函数返回值对应的内容
    • 使用函数名称作为组件标签名称
// 使用 双标签 渲染组件:
<Hello></Hello>
ReactDOM.render(<Hello></Hello>, root)// 使用 单标签 渲染组件:
<Hello />
ReactDOM.createRoot(document.querySelector('#root')).render(<Hello></Hello>)

小结

  1. 在react中可以使用函数或者箭头函数创建组件
  2. 组件的首字母必须大写

2.2 类组件

内容

  • 使用 ES6 的 class 创建的组件,叫做类(class)组件
  • 约定1:类名称也必须以大写字母开头
  • 约定2:类组件应该继承 React.Component 父类,从而使用父类中提供的方法或属性
  • 约定3:类组件必须提供 render 方法
  • 约定4:render 方法必须有返回值,表示该组件的 UI 结构

定义组件

// 导入 React
import React from 'react'
class Hello extends React.Component {render() {return <div>Hello Class Component!</div> }
}
ReactDOM.render(<Hello />, root)// 只导入 Component
import { Component } from 'react'
class Hello extends Component {render() {return <div>Hello Class Component!</div> }
}

使用组件

ReactDOM.createRoot(document.querySelector('#root')).render(<Hello></Hello>)

总结

  1. 使用class语法创建组件比函数创建稍微麻烦一些,但是类组件的功能会比函数组件的功能更加强大(hooks 之前

三、将组件提取到单独的js文件中

实现方式

  1. 创建 Hello.js
  2. 创建组件(函数 或 类)
  3. 在 Hello.js 中导出该组件
  4. 在 index.js 中导入 Hello 组件
  5. 渲染组件

核心代码

// index.js
//直接导入
import Hello from './Hello'//按需导入
// import {Hello} from './Hello'// 渲染导入的Hello组件
ReactDOM.createRoot(document.querySelector('#root')).render(<Hello></Hello>)// Hello.js
import { Component } from 'react'
class Hello extends Component {render() {return <div>Hello Class Component!</div>}
}
// 导出Hello组件(默认导出)
export default Hello//按需导出
// export {
//	Hello
// }

四、有状态组件和无状态组件

内容

  • 函数组件又叫做无状态组件 函数组件是不能自己提供数据【前提:不考虑 hooks 的情况下】
  • 类组件又叫做有状态组件 类组件可以自己提供数据
  • 状态state是组件的私有数据,当组件的状态发生了改变,页面结构也就发生了改变(数据驱动视图
  • 函数组件是没有状态的,只负责页面的展示态,不会发生变化),性能比较高
  • 类组件有自己的状态,负责更新UI,只要类组件的数据发生了改变,UI 就会发生更新态)
  • 在项目中,一般都是由函数组件和类组件共同配合来完成的

比如计数器案例,点击按钮让数值+1, 0和1就是不同时刻的状态,当状态从0变成1之后,UI也要跟着发生变化。React想要实现这种功能,就需要使用有状态组件来完成。

  • 函数组件和类组件的区别:有没有状态【前提:不考虑 hooks 的情况下】

五、类组件的状态

内容

  • 状态state,即数据,是组件内部的私有数据,只能在组件内部使用
  • 状态 state 的值是对象,表示一个组件中可以有多个数据
  • 通过 this.state.xxx 来获取状态

核心代码

  • 创建 state
class Hello extends Component {// 为组件提供状态state = {count: 0,list: [],isLoading: true}render() {return (<div>计数器</div>)}
}
  • 读取状态:通过 this.state 来获取状态
class Hello extends Component {// ...render() {// 通过 this.state 来访问类组件的状态return (<div>计数器:{this.state.count}</div>)}
}

六、事件处理

6.1 注册事件

内容

  • React注册事件与DOM的事件语法非常像

  • 语法on+事件名 ={事件处理程序} 比如onClick={this.handleClick}

  • 注意:React事件采用驼峰命名法,比如onMouseEnter, onClick

核心代码

class App extends React.Component {handleClick() {console.log('点击事件触发')}render() {return (<div><button onClick={this.handleClick}>点我</button></div>)}
}

6.2 事件对象

核心代码

  • 可以通过事件处理程序的参数获取到事件对象
  • 注意:React 中的事件对象是 React 内部处理后的事件对象,一般称为:SyntheticBaseEvent 合成事件对象。用法与 DOM 原生的事件对象用法基本一致
function handleClick(e) {e.preventDefault()console.log('事件对象', e)
}<a onClick={this.handleClick}>点我,不会跳转页面</a>

6.3 this指向问题

内容:

  • 事件处理程序中的this指向的是undefined

  • render方法中的this指向的是当前react组件。只有事件处理程序中的this有问题

  • 原因

    • 事件处理程序的函数式函数调用模式,在严格模式下,this指向undefined
    • render函数是被组件实例调用的,因此render函数中的this指向当前组件
class App extends React.Component {state = {msg: 'hello react'}handleClick() {console.log(this.state.msg)}render() {return (<div><button onClick={this.handleClick}>点我</button></div>)}
}

总结

  1. 在react的事件处理函数中,this指向undefined

6.4 this指向解决方案

内容

  • 解决事件处理程序中this指向问题主要有三种方式

  • 方式1:箭头函数

class App extends React.Component {state = {msg: 'hello react'}handleClick() {console.log(this.state.msg)}render() {return (<div><button onClick={() => this.handleClick()}>点我</button></div>)}
}
  • 方式2:bind
class App extends React.Component {state = {msg: 'hello react'}handleClick() {console.log(this.state.msg)}render() {return (<div><button onClick={this.handleClick.bind(this)}>点我</button></div>)}
}
  • 方式3:箭头函数形式的实例方法 - 推荐使用
class App extends React.Component {state = {msg: 'hello react'}handleClick = () => {console.log(this.state.msg)}render() {return (<div><button onClick={this.handleClick}>点我</button></div>)}
}

总结

  1. 推荐使用方式3,箭头函数形式的实例方法
  • 解释为什么方式3可以解决 this 指向问题:
// ES6
class Person1 {// 类的 构造函数constructor() {// 构造函数中的 this 就是实例对象console.log(this)this.name = 'jack'this.fn = () => {console.log(this)}}// 上述写法简化语法:// name = 'jack'// fn = () => {}// 这个形式的方法会被添加到原型中sayHi() {}
}说明:fn = () => {}  这种形式的语法是简化语法(语法糖),书写会更简单。实际上,完整的写法是:constructor() {this.fn = () => {}
}即:在构造函数中,给 this 添加了一个方法 fn为什么可以解决 this 指向问题呢?
因为 constructor 中创建的箭头函数,内部的 this 会指向 constructor 中的 this
而 constructor 中的 this 就是实例对象(也就是我们需要的 this

七、setState 修改状态

内容

  • 语法:this.setState({ 要修改的部分数据 })
  • setState() 作用:1 修改 state 2 更新 UI
  • 思想:数据驱动视图,也就是只需要修改数据(状态)那么页面(视图)就会自动刷新
    • 核心:数据!!!
    • 从现在开始,我们关心的是如何修改数据,而不再是关心如何修改DOM
    • 并且,注意:尽量避免直接手动 DOM(通过 document.querySelector() 获取到到DOM对象然后再操作) 操作!!!
  • 注意:不要直接修改 state 中的值,这是无效的

核心代码

class Hello extends Component {state = {count: 0}handleClick = () => {this.setState({count: 10})}  render() {return (<div><h1>计数器:{this.state.count}</h1><button onClick={this.handleClick}>+1</button></div>)}
}// 在 count 当前值的基础上加 1
this.setState({count: this.state.count + 10
})

总结

  1. 能直接修改 state 的值吗?不能
  2. 如何修改 React 组件中的状态?setState()
  3. setState 是哪来的?从 Component 父类继承过来的

八、react核心理念(状态不可变)

内容:

  • 状态不可变指的是:不要直接修改状态的值,而是基于当前状态创建新的状态值

核心代码

state = {count: 0,list: [1, 2, 3],person: {name: 'jack',age: 18}
}// 【不推荐】直接修改当前值的操作:
this.state.count++
++this.state.count
this.state.count += 1
this.state.count = 1// 只要是数组中直接修改当前数组的方法都不能用!
this.state.list.push(123)this.state.person.name = 'rose'// 【推荐】不是直接修改当前值,而是创建新值的操作:
this.setState({count: this.state.count + 1,list: [...this.state.list, 123],person: {...this.state.person,// 要修改的属性,会覆盖原来的属性,这样,就可以达到修改对象中属性的目的了name: 'rose'}
})

九、表单处理

9.1 受控组件

内容

  • HTML中表单元素是可输入的,即表单元素维护着自己的可变状态(value)
  • 但是在react中,可变状态通常是保存在state中的,并且要求状态只能通过setState进行修改
  • React中将state中的数据与表单元素的value值绑定到了一起,由state的值来控制表单元素的值
  • 受控组件:value值受到了react状态控制的表单元素

核心代码:

class App extends React.Component {state = {msg: 'hello react'}handleChange = (e) => {this.setState({msg: e.target.value})}render() {return (<div><input type="text" value={this.state.msg} onChange={this.handleChange}/></div>)}
}

总结

  1. 使用受控组件的方式处理表单元素后,状态的值就是表单元素的值。即:想要操作表单元素的值,只需要操作对应的状态即可*

9.2 非受控组件-ref

非受控组件借助于ref,使用原生DOM的方式来获取表单元素的值
内容

  • 受控组件是通过 React 组件的状态来控制表单元素的值
  • 非受控组件是通过手动操作 DOM 的方式来控制
  • 此时,需要用到一个新的概念:ref
  • ref:用来在 React 中获取 DOM 元素

核心代码

// 1 导入 createRef 函数( 用来创建 ref 对象 )
import { createRef } from 'react'class Hello extends Component {// 2 调用 createRef 函数来创建一个 ref 对象//   ref 对象的名称(txtRef)可以是任意值//   命名要规范: txt(DOM 元素的自己标识) + ReftxtRef = createRef()handleClick = () => {// 文本框对应的 DOM 元素// console.log(this.txtRef.current)// 4 获取文本框的值:console.log(this.txtRef.current.value)}render() {return (<div>{/*3 将创建好的 ref 对象,设置为 input 标签的 ref 属性值作用:将 ref 和 input DOM 绑定到一起,将来在通过 this.txtRef 拿到的就是当前 DOM 对象*/}<input ref={this.txtRef} /><button onClick={this.handleClick}>获取文本框的值</button></div>)}
}

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

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

相关文章

【设计模式】单例设计模式详解(包含并发、JVM)

文章目录 1、背景2、单例模式3、代码实现1、第一种实现&#xff08;饿汉式&#xff09;为什么属性都是static的&#xff1f;2、第二种实现&#xff08;懒汉式&#xff0c;线程不安全&#xff09;3、第三种实现&#xff08;懒汉式&#xff0c;线程安全&#xff09;4、第四种实现…

day38-Mobile Tab Navigation(手机tab栏导航切换)

50 天学习 50 个项目 - HTMLCSS and JavaScript day38-Mobile Tab Navigation&#xff08;手机tab栏导航切换&#xff09; 效果 index.html <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"…

3ds MAX 洗菜池

在家居中我们显然离不开这个对吧 首先绘制一个长方体作为基础 注意设置长宽高的网格大小&#xff0c;方便后续调整 俯视图网格线如下&#xff1a; 长方形变换为可编辑网络&#xff0c;并在【多边形】界面选择底面的所有多边形&#xff0c;按delete删除&#xff0c;形成一个壳体…

Github上方导航栏介绍

Code Watch&#xff1a;相当于关注&#xff0c;到时候这个项目又有什么操作&#xff0c;就会以通知的形式提醒你。 Fork&#xff1a;也就是把这个项目拉到你的仓库里&#xff0c;之后你可以对该代码进行修改&#xff0c;之后你可以发起Pull Request&#xff0c;简称PR&#xf…

vulnhub靶场之CengBox3

1.信息收集 输入命令&#xff1a;netdiscover -i eth0 -r 192.168.239.0 &#xff0c;发现181机器存活 输入命令nmap -p- -sV -O -Pn -A 192.168.239.181 &#xff0c;进行端口探测&#xff0c;发现存在22、80、443端口&#xff0c;还发现存在域名ceng-company.vm。 将域名c…

了解Unity编辑器之组件篇Tilemap(五)

Tilemap&#xff1a;用于创建和编辑2D网格地图的工具。Tilemap的主要作用是简化2D游戏中地图的创建、编辑和渲染过程。以下是一些Tilemap的主要用途&#xff1a; 2D地图绘制&#xff1a;Tilemap提供了一个可视化的编辑器界面&#xff0c;可以快速绘制2D地图&#xff0c;例如迷…

docker版jxTMS使用指南:新建用户并授权

本文讲解4.4版jxTMS中如何新建用户并授权&#xff0c;整个系列的文章请查看&#xff1a;[docker版jxTMS使用指南&#xff1a;docker版jxTMS使用指南&#xff1a;4.4版升级内容 docker版本的使用&#xff0c;请查看&#xff1a;docker版jxTMS使用指南 4.0版jxTMS的说明&#x…

python实现逻辑回归-清风数学建模-二分类水果数据

所用数据 &#x1f449;&#x1f449;&#x1f449;二分类水果数据 1.数据预处理 可以看到有4个特征&#xff0c;2种分类结果&#xff0c;最后4个没有分类结果的数据是拿来预测的 # 1. 数据预处理 import pandas as pd df pd.read_excel(oridata/二分类水果数据.xlsx,use…

开源大模型LLaMA 2会扮演类似Android的角色么?

在AI大模型没有商业模式&#xff1f;等文章中&#xff0c;我多次表达过这样一个观点&#xff1a;不要把大模型的未来应用方式比喻成公有云&#xff0c;大模型最终会是云端操作系统的核心&#xff08;新通用计算平台&#xff09;&#xff0c;而它的落地形式会很像过去的沃森&…

【C++】开源:Linux端ALSA音频处理库

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍Linux端ALSA音频处理库。 无专精则不能成&#xff0c;无涉猎则不能通。。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&#xff0c…

Python增删改查小练习

目录 1. List操作-增加 2. List操作-查询 3. List操作-修改 4. List操作-删除 资料获取方法 1. List操作-增加 List Append(“xx”) 插入到列表尾部 Insert(x,xx) 在指定的位置插入 Extend 将列表的元素分开,插入到之前列表的尾部 小练习: 把一个字符串”abcdefg…

ssh打开远程vscode

如果想要远程打开其他终端的vscode&#xff0c;首先要知道远程终端的ip地址和用户名称以及用户密码 1、打开本地vscode 2、点击左下角蓝色区域 3、页面上部出现如下图&#xff0c;点击ssh&#xff0c;我这里已经连接&#xff0c;所以是connect to host 4、选择Add New SSH Host…

线程池几个核心参数说明

线程池几个核心参数 corePoolSize&#xff1a;核心线程数量大小。maximumPoolSize&#xff1a;线程池最大容纳线程数。keepAliveTime&#xff1a;线程空闲后的存活时长。TimeUnit&#xff1a;单位时间。BlockingQueue&#xff1a;缓存异步任务的队列。 ThreadFactory &#xff…

appium中toast识别

目录 一、什么是Toast&#xff1f; 二、环境前提 三、修改配置 四、安装驱动 五、常见报错及解决方案 1、cnpm 不识别&#xff0c;提示不是内部或外部命令 2、npm 也不识别 3、报错 六、代码节选 一、什么是Toast&#xff1f; Android中的Toast是一种简易的消息提示框…

比selenium体验更好的ui自动化测试工具: cypress介绍

话说 Cypress is a next generation front end testing tool built for the modern web. And Cypress can test anything that runs in a browser.Cypress consists of a free, open source, locally installed Test Runner and a Dashboard Service for recording your tests.…

AutoSAR系列讲解(实践篇)9.1-协议数据单元PDU

本章主要是讲解通信(不包括诊断和标定的纯通信),同样是主要以CAN来讲解。由于通信大家其实用的基本上是其最基础的功能,所以本章的实验主要就是教大家如何配置基础通信,但是高级一点的功能,博主也会在前面这几节给大家讲到,用不到的同学仅作了解就行。同样,忘了通信是怎…

day44-Spring_AOP

0目录 1.2.3 1.Spring_AOP 实体类&#xff1a; Mapper接口&#xff1a; Service和实现类&#xff1a; 测试1&#xff1a; 运行后&#xff1a; 测试2&#xff1a;无此型号时 测试3&#xff1a;库存不足时 解决方案1&#xff1a;事务声明管理器 测试&#xff1a…

Grub2基础上添加Windows引导和临时启动Windows

grub2临时启动Windows 在引导列表页按c进入Grub2终端 。 insmod part_gpt set root(hd0, 1) chainloader /efi/Microsoft/Boot/bootmgfw.efi bootinsmod part_gpt 导入模块&#xff0c;让grub可以看到gpt格式的硬盘&#xff08;这个有没有必要我也不清楚&#xff0c;但执行…

WPF实战学习笔记06-设置待办事项界面

设置待办事项界面 创建待办待办事项集合并初始化 TodoViewModel&#xff1a; using Mytodo.Common.Models; using Prism.Commands; using Prism.Mvvm; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using Sy…

RocketMQ主从集群broker无法启动,日志报错

使用vmWare安装的centOS7.9虚拟机&#xff0c;RocketMQ5.1.3 在rocketMQ的bin目录里使用相对路径的方式启动broker&#xff0c;jps查询显示没有启动&#xff0c;日志报错如下 排查配置文件没有问题&#xff0c;nameServer也已经正常启动 更换绝对路径&#xff0c;启动broker&…