react-组件基础

1.目标

能够使用函数创建组件
能够使用class创建组件
能够给React元素绑定事件
能够使用state和setState()
能够处理事件中的this指向问题
能够使用受控组件方式处理表单

2.目录

React组件介绍
React组件的两种创建方式
React事件处理
有状态组件和无状态组件
组件中的state和setState()
事件绑定this指向
表单处理

3.react组件介绍

组件是React的一等公民,使用React就是在用组件
组件表示页面中的部分功能
组合多个组件实现完整的页面功能
特点:可复用、独立、可组合

4.react组件的两种创建方式

A. 使用函数创建组件
B. 使用类创建组件

4.1 使用函数创建组件

A. 函数组件:使用JS的函数(或箭头函数)创建的组件
B. 约定1:函数名称必须以大写字母开头
C. 约定2:函数组件必须有返回值,表示该组件的结构
D. 如果返回值为null,表示不渲染任何内容

function Hello(){
return (
<div>这是我的第一个函数组件</div>
)
}

A. 渲染函数组件:用函数名作为组件标签名
B. 组件标签可以是单标签也可以是双标签

ReactDOM.render(<Hello></Hello>,document.getElementById('root'))

4.2 使用类创建组件

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

class Hello1 extends React.Component{
render(){
return (
<div>
我是一个类组件
</div>
)
}
}
ReactDOM.render(<Hello1 />,document.getElementById('root'))

4.3 抽离为单独JS文件

A. 思考:项目中的组件多了之后,该如何组织这些组件呢?
B. 选择一:将所有组件放在同一个JS文件中
C. 选择二:将每个组件放到单独的JS文件中
D. 组件作为一个独立的个体,一般都会放到一个单独的JS文件中
E. 抽离步骤:
\1. 创建Hello.js
\2. 在Hello.js中导入React
\3. 创建组件(函数或类)
\4. 在Hello.js中导出该组件
\5. 在index.js中导入Hello组件
\6. 渲染组件
在这里插入图片描述

5.React事件处理

\1. 事件绑定
\2. 事件对象

5.1 事件绑定

A. React事件绑定语法与DM事件语法相似
B. 语法:on+事件名称=[事件处理程序],比如:onClick={()=>{}}
C. 注意:React事件采取驼峰命名法,比如:onMouseEnter、onFocus
D. 在函数组件绑定事件:
Index.js(函数事件绑定)

// 函数组件事件绑定
function Hello() {function clickHandle() {console.log("函数事件触发了");}return <button onClick={clickHandle}>点击触发函数事件</button>;
}ReactDOM.createRoot(document.getElementById("root")).render(<Hello></Hello>);

index.js(类事件绑定)

// 类事件绑定
class Hello2 extends React.Component {clickHandle() {console.log("类事件触发了");}render() {return <button onClick={this.clickHandle}>点击触发类事件</button>;}
}ReactDOM.createRoot(document.getElementById("root")).render(<Hello2></Hello2>);

区别:
在这里插入图片描述

5.2 事件对象

A. 可以通过事件处理程序的参数获取到事件对象
B. React中的事件对象叫做:合成事件(对象)
C. 合成事件:兼容所有浏览器,无需担心跨浏览器兼容性问题

// 事件对象
class App extends React.Component {clickHandel(e) {// 阻止浏览器默认行为e.preventDefault();console.log("点击事件触发了");}render() {return (<a href="https://www.baidu.com" onClick={this.clickHandel}>百度</a>);}
}ReactDOM.createRoot(document.getElementById("root")).render(<App></App>);

6.有状态组件和无状态组件

A. 函数组件又叫做无状态组件,类组件又叫做有状态组件
B. 状态(state)即数据
C. 函数组件没有自己的状态,只负责数据展示(静)
D. 类组件有自己的状态,负责更新UI,让页面”动”起来
比如计算器案例中,点击按钮让数值加1。0和1就是不同时刻的状态,而由0变为1就表示状态发生了变
化。状态变化后,UI也要相应的更新。React中想要实现该功能,就要使用有状态组件来完成。
在这里插入图片描述

7.组件中的state和setState

A. state的基本使用
B. setState()修改状态

7.1 state的基本使用

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

// 有状态组件
class Hello3 extends React.Component {constructor() {super(); // 必须写}state = {count: 0,};render() {return (<div>有状态组件<h1>计数器:{this.state.count}</h1></div>);}
}ReactDOM.createRoot(document.getElementById("root")).render(<Hello3></Hello3>);

7.2 setState()修改状态

A. 状态是可变的
B. 语法:this.setState({要修改的数据})
C. 注意:不要直接修改state中的值,这是错误的!!!!
D. setState()作用:1.修改state 2.更新UI
E. 思想:数据驱动视图

// 有状态组件
class Hello3 extends React.Component {constructor() {super(); // 必须写}state = {count: 0,};render() {return (<div>有状态组件<h1>计数器:{this.state.count}</h1><buttononClick={() => {this.setState({ count: this.state.count + 1 });}}>+1</button></div>);}
}ReactDOM.createRoot(document.getElementById("root")).render(<Hello3></Hello3>);

7.3 从JSX中抽离事件处理程序

A. JSX中掺杂过多JS逻辑代码,会显得非常混乱
B. 推荐:将逻辑抽离到单据的方法中,保证JSX结构清晰
在这里插入图片描述
在这里插入图片描述

// 有状态组件
class Hello3 extends React.Component {constructor() {super(); // 必须写}state = {count: 0,};onIncrement() { console.log(this, "抽离出来的this");this.setState({count: this.state.count + 2,});}render() {return (<div>有状态组件<h1>计数器:{this.state.count}</h1><buttononClick={() => {console.log(this, "函数式事件触发的this");this.setState({ count: this.state.count + 1 });}}>+1</button><button onClick={this.onIncrement}>+2</button></div>);}
}ReactDOM.createRoot(document.getElementById("root")).render(<Hello3></Hello3>);

A. 原因:事件处理程序中this的值为undefined—抽离出来的方法用箭头函数可解决
B. 希望:this指向组件实例(render方法中的this即为组件实例)
把state放在,构造函数里面

8.事件绑定this指向

A. 抽离出的事件处理函数使用箭头函数
B. Function.prototype.bind() 【在构造函数中使用.bind(this)来绑定this上下文】
C. 在render方法中使用箭头函数来调用onIncrement,但这样每次渲染都会创建一个新的函数,可能会影响性能

8.1 箭头函数

A. 利用箭头函数自身不绑定this的特点
B. Render()方法中的this为组件实例,可以获取到setState()
在这里插入图片描述

8.2 在构造函数中使用.bind(this)来绑定this上下文–Function.prototype.bind()

在这里插入图片描述

8.3 在render方法中使用箭头函数来调用onIncrement,但这样每次渲染都会创建一个新的函数,可能会影响性能

<button onClick={() => this.onIncrement()}>+2</button>

9.表单处理

\1. 受控组件
\2. 非受控组件(DOM方式)

9.1 受控组件

A. HTML中的表单元素是可输入的,也就是有自己的可变状态
B. 而,React中可变状态通常保存在state,并且只能通过setState()方法来修改
C.React将state与表单元素值value绑定到一起,由state的值来控制表单元素的值
D. 受控组件:其值受到React控制的表单元素
E. 步骤
\1. 在state中添加一个状态,作为表单元素的value值(控制表单元素值的来源)
\2. 给表单元素绑定change事件,将表单元素的值设置为state的值(控制表单元素值的变化)

class Hello4 extends React.Component {constructor() {super();this.state = {txt: "默认值",};}inputHandle = (e) => {this.setState({txt: e.target.value,});};render() {return (<div>文本的值:{this.state.txt}<br /><inputtype="text"value={this.state.txt}onChange={this.inputHandle}></input></div>);}
}ReactDOM.createRoot(document.getElementById("root")).render(<Hello4></Hello4>);

示例:
A.文本框、富文本框、下拉框
B.复选框

class Hello4 extends React.Component {constructor() {super();this.state = {txt: "默认值",content: "",city: "zj",isChecked: true,};}handleChange1 = (e) => {this.setState({txt: e.target.value,});};handleChange2 = (e) => {this.setState({content: e.target.value,});};handleChange3 = (e) => {this.setState({city: e.target.value,});};handleChange4 = (e) => {console.log(e, "e4");this.setState({isChecked: e.target.checked,});};render() {return (<div>{/* 输入框 */}文本的值:{this.state.txt}<inputtype="text"value={this.state.txt}onChange={this.handleChange1}></input><br />{/* 文本框 */}文本框的值:{this.state.content}<textareavalue={this.state.content}onChange={this.handleChange2}></textarea><br />{/* 下拉框 */}下拉框的值:{this.state.city}<select value={this.state.city} onChange={this.handleChange3}><option value="zj">浙江</option><option value="js">江苏</option><option value="sh">上海</option><option value="bj">北京</option></select><br />{/* 复选框 */}复选框的值:{this.state.isChecked}<inputtype="checkbox"checked={this.state.isChecked}onChange={this.handleChange4}></input></div>);}
}ReactDOM.createRoot(document.getElementById("root")).render(<Hello4></Hello4>);

9.1.1 多表单元素优化

A. 问题:每个表单元素都有一个单独的事件处理程序处理太繁琐
B. 优化:使用一个事件处理程序同时处理多个表单元素

9.1.2 多表单元素优化步骤

A. 给表单元素添加name属性,名称与state相同
B. 根据表单元素类型获取对应值
C. 在change事件处理程序中通过[name]来修改对应的state

class Hello4 extends React.Component {constructor() {super();this.state = {txt: "默认值",content: "",city: "zj",isChecked: true,};}handleForm = (e) => {const value =e.target.type === "checkbox" ? e.target.checked : e.target.value;this.setState({[e.target.name]: value,});};render() {return (<div>{/* 输入框 */}文本的值:{this.state.txt}<inputtype="text"name="txt"value={this.state.txt}onChange={this.handleForm}></input><br />{/* 文本框 */}文本框的值:{this.state.content}<textareaname="content"value={this.state.content}onChange={this.handleForm}></textarea><br />{/* 下拉框 */}下拉框的值:{this.state.city}<select value={this.state.city} name="city" onChange={this.handleForm}><option value="zj">浙江</option><option value="js">江苏</option><option value="sh">上海</option><option value="bj">北京</option></select><br />{/* 复选框 */}复选框的值:{this.state.isChecked}<inputtype="checkbox"name="isChecked"checked={this.state.isChecked}onChange={this.handleForm}></input></div>);}
}ReactDOM.createRoot(document.getElementById("root")).render(<Hello4></Hello4>);

9.2 非受控组件

A. 说明:借助于ref,使用原生DOM方法来获取表单元素值
B. ref的作用:获取DOM或组件
C. 使用步骤:

  1. 调用React.createRef()方法创建一个ref对象
  2. 将创建好的ref对象添加到文本框中
  3. 通过ref对象获取到文本框的值
class Hello6 extends React.Component {constructor() {super();// 创建Refthis.textRef = React.createRef();}getText = () => {console.log(this.textRef);console.log(this.textRef.current.value);};render() {return (<div><input type="text" ref={this.textRef}></input><button onClick={this.getText}>获取文本框的值</button></div>);}
}
ReactDOM.createRoot(document.getElementById("root")).render(<Hello6></Hello6>);

10.react组件基础-案例评论列表

index.js

class Comment extends React.Component {constructor() {super();// 初始化值this.state = {userName: "",userContent: "",comments: [{ id: 1, name: "周可可", content: "大家好,我是周可可~~" },{ id: 2, name: "周嫑嫑", content: "每没有人能欺负周可可!!!" },{ id: 3, name: "周深", content: "大家好,我是周深~~" },{ id: 4, name: "周浅", content: "大家好,我是周浅~~" },],};}// 数据展示renderList = () => {return this.state.comments.length == 0 ? (<div>暂无评论,快去发布吧~</div>) : (<div><ul className="contentDetailBox">{this.state.comments.map((item) => (<li key={item.id}>评论人:{item.name}<br />评论内容:{item.content}</li>))}</ul></div>);};// 数据响应式changeForm = (e) => {const { name, value } = e.target;this.setState({[name]: value,});};// 添加addComment = () => {let { userName, userContent, comments } = this.state;// 非空校验if (userName.trim() == "" || userContent.trim() == "") {return alert("用户名或评论内容不能为空!");}const newComments = [{id: comments.length > 0 ? comments.length + 1 : 1,name: userName,content: userContent,},...comments,];console.log(newComments, "newComments");this.setState({ comments: newComments });// 清空数据this.state.userName = "";this.state.userContent = "";};render() {const { userName, userContent } = this.state;return (<div><div className="appp"><h1>评论</h1><div><inputname="userName"placeholder="请输入评论人"className="userIpt"value={userName}onChange={this.changeForm}></input></div><br /><div style={{ marginBottom: "10px" }}><textareaname="userContent"placeholder="请输入评论内容"rows={10}cols={50}className="contentTextarea"value={userContent}onChange={this.changeForm}></textarea></div><button onClick={this.addComment}>发布评论</button><div><h2 style={{ textAlign: "center" }}>评论详情</h2>{this.renderList()}</div></div></div>);}
}ReactDOM.createRoot(document.getElementById("root")).render(<Comment></Comment>
);

index.css

.appp {width: 35%;height: 700px;border: 1px solid gray;padding-left: 50px;
}.appp h1 {text-align: center;
}.userIpt {width: 40%;
}.contentDetailBox {height: 300px;overflow-y: scroll;
}

在这里插入图片描述

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

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

相关文章

4G工牌室内外定位系统

4G工牌室内外定位系统是一种高效、精准的定位技术&#xff0c;它利用4G通信网络和GPS卫星定位系统&#xff0c;实现了对人员和物品的实时跟踪和定位。该系统广泛应用于企业管理、安全监控、智能交通等领域&#xff0c;为企业提供了更加高效、便捷的管理方式。 在室内环境中&am…

链表(C语言版)超详细讲解

链表 链表基础 一、链表的概念 定义&#xff1a; 链表是一种物理存储上非连续&#xff0c;数据元素的逻辑顺序通过链表中的指针链接次序&#xff0c;实现的一种线性存储结构。二、链表的构成 构成&#xff1a;链表由一个个结点组成&#xff0c;每个结点包含两个部分&#xff1…

全网最详细的Jmeter接口自动化测试

前面我们复习了jmeter 的非图形化界面运行我们的测试接口。 大家可以翻看往期jmeter的文章。 具体来说就是&#xff1a;jmeter -n -t ****.jmx -l ****.jtl -e -o **** (*号代表路径&#xff09; 生成了测试报告。 但是这个非图形化运行有个缺点&#xff0c;就是只能运…

蓝牙资产标签信标

随着科技的不断进步&#xff0c;蓝牙技术的应用已经深入到我们的日常生活中。其中&#xff0c;蓝牙资产标签作为一种新型的资产管理方式&#xff0c;正逐渐受到广泛欢迎。蓝牙资产标签是一种基于蓝牙技术的小型电子标签&#xff0c;可以粘贴在各种资产上&#xff0c;通过手机或…

代码随想录算法训练营第27天—贪心算法01 | ● 理论基础 ● 455.分发饼干 ● 376. 摆动序列 ● 53. 最大子序和

理论基础 https://programmercarl.com/%E8%B4%AA%E5%BF%83%E7%AE%97%E6%B3%95%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html 贪心算法的本质&#xff1a;由局部最优推到全局最优贪心算法的套路&#xff1a;无固定套路 455.分发饼干 https://programmercarl.com/0455.%E5%88%8…

(白盒测试)简单循环测试

简单循环测试 1.为什么要引入简单循环测试&#xff1f; 用来测试代码中的循环结构是否能正常执行 是否会少执行一次&#xff1f;多执行一次&#xff1f; 通过循环测试就可以得知 2.什么是简单循环&#xff1f; 没有嵌套的循环⇒简单循环 比如 单层的for循环 单层的while循…

【Qt】鼠标拖拽修改控件尺寸---八个方位修改

前提 在开发一个类似qdesiger的项目中 使用QGraphicsProxyWidget将Qt基础控件作为item放在场景视图中显示和编辑 创建自定义类继承QGraphicsProxyWidget&#xff0c;管理控件 成员变量 有控件的xywh等&#xff0c;其中x、y坐标存储是基于最底层widgetitem的 坐标系 x轴以右为正…

anaconda指定目录创建环境无效/环境无法创建到指定位置

已经设置目录到D盘 创建环境时还是分配到C盘 可能是指定位置没有开启读写权限&#xff0c;如我在这里安装到了anaconda文件夹&#xff0c;则打开该文件夹的属性->安全->编辑 allusers下的权限全都打勾

【DAY05 软考中级备考笔记】线性表,栈和队列,串数组矩阵和广义表

线性表&#xff0c;栈和队列&#xff0c;串数组矩阵和广义表 2月28日 – 天气&#xff1a;阴转晴 时隔好几天没有学习了&#xff0c;今天补上。明天发工资&#xff0c;开心&#x1f604; 1. 线性表 1.1 线性表的结构 首先线性表的结构分为物理结构和逻辑结构 物理结构按照实…

动态规划之使用最小花费爬楼梯【LeetCode】

动态规划之使用最小花费爬楼梯 LCR 088. 使用最小花费爬楼梯解法1解法2 LCR 088. 使用最小花费爬楼梯 LCR 088. 使用最小花费爬楼梯 解法1 状态表示&#xff08;这是最重要的&#xff09;&#xff1a;dp[i]表示以第i级台阶为楼层顶部&#xff0c;到达第i层台阶的最低花费。 状…

LeetCode_Java_移除链表元素(题目+思路+代码)

203.移除链表元素 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,6,3,4,5,6], val 6 输出&#xff1a;[1,2,3,4,5]思路&#xff1a;…

idea打包报错,clean、package报错

一、idea在打包时&#xff0c;点击clean或package报错如下&#xff1a; Error running ie [clean]: No valid Maven installation found. Either set the home directory in the configuration dialog or set the M2_HOME environment variable on your system. 示例图&#xf…

从0开始python学习-53.python中flask创建简单接口

目录 1. 创建一个简单的请求,没有写方法时默认为get 2. 创建一个get请求 3. 创建一个post请求&#xff0c;默认可以使用params和表单传参 4. 带有参数的post请求 1. 创建一个简单的请求,没有写方法时默认为get from flask import Flask, request# 初始化一个flask的对象 ap…

Python入门学习:if语句与条件控制--and、or、in、not in详解与实践

Python入门学习&#xff1a;if语句与条件控制–and、or、in、not in详解与实践 &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程&#x1…

42.do...while语句

目录 一.什么是do...while语句 二.语法 三.执行流程图 四.举例 五.视频教程 一.什么是do...while语句 do...while语句也是循环语句&#xff0c;和while语句的区别是&#xff0c;while语句是先判断表达式&#xff0c;如果表达式成立才会执行循环体中的内容&#xff0c;否则…

【vmware安装群晖】

vmware安装群晖 vmware安装群辉&#xff1a; vmware版本&#xff1a;17pro 下载链接&#xff0c; https://customerconnect.vmware.com/cn/downloads/details?downloadGroupWKST-1751-WIN&productId1376&rPId116859 激活码可自行搜索 教程&#xff1a; https://b…

【数据结构(C语言)】排序详解

目录 文章目录 前言 一、排序的概念 1.1 排序的概念 1.2 常见的排序算法 二、插入排序 2.1 直接插入排序 2.1.1 基本思想 2.1.2 特性总结 2.1.3 代码实现 2.2 希尔排序 2.2.1 基本思想 2.2.2 特性总结 2.2.3 代码实现 三、选择排序 3.1 直接选择排序 3.1.1…

【技术杂谈】关于线程池在生产环境中的使用

欢迎关注公众号&#xff08;通过文章导读关注&#xff1a;【11来了】&#xff09;&#xff0c;及时收到 AI 前沿项目工具及新技术的推送&#xff01; 在我后台回复 「资料」 可领取编程高频电子书&#xff01; 在我后台回复「面试」可领取硬核面试笔记&#xff01; 文章导读地址…

快讯|Tubi 更新内容库重新定义自己

在每月一期的 Tubi 快讯中&#xff0c;你将全面及时地获取 Tubi 最新发展动态&#xff0c;欢迎&#x1f31f;星标关注【比图科技】&#xff0c;一起成长变强&#xff01; Tubi 更新内容库&#xff0c;重新定义自己 Tubi 近日宣布为数千万用户免费提供备受观众喜爱、获奖无数的…

Python多线程编程:深入理解threading模块及代码实战【第99篇—Multiprocessing模块】

Python多线程编程&#xff1a;深入理解threading模块及代码实战 在Python编程中&#xff0c;多线程是一种常用的并发编程方式&#xff0c;它可以有效地提高程序的执行效率&#xff0c;特别是在处理I/O密集型任务时。Python提供了threading模块&#xff0c;使得多线程编程变得相…