苏州专业设计网站,济南seo排名优化推广,宿迁专业网站三合一建设,河北邯郸建网站一、组件的概念
使用组件方式进行编程#xff0c;可以提高开发效率#xff0c;提高组件的复用性、提高代码的可维护性和可扩展性
React定义组件的方式有两种 类组件#xff1a;React16.8版本之前几乎React使用都是类组件 函数组件:React16.8之后#xff0c;函数式组件使…一、组件的概念
使用组件方式进行编程可以提高开发效率提高组件的复用性、提高代码的可维护性和可扩展性
React定义组件的方式有两种 类组件React16.8版本之前几乎React使用都是类组件 函数组件:React16.8之后函数式组件使用的越来越多
二、组件定义
1、ES6类的回顾
类组件类组件是指使用ES6中class定义的组件称为类组件
回顾类的定义
class 类名{}
类是由属性和方法组成 类中的属性表示的事物的特征 类中方法表示的是对象的行为
class 类名{属性名1;属性名2;方法名1(){}方法名2(){}
}
案例1类的定义
/*定义一个学生类class 类名{
}类名的规定1、类名是由字母、数字、下划线或者$符号组成2、名称不能以数字开头3、类名之间不能由空格、不能是关键字或者保留字4、不能是true,false,null5、类名采用驼峰式命名法每个单词的首字母要大写6、要见名知意
*/
class Student{sno; //学号sname; //姓名gender; //性别education; //学历major; //专业introduce(){return 学号:${this.sno}\n姓名:${this.sname}\n性别:${this.gender}\n学历:${this.education}\n专业:${this.major}}
}
/*创建对象的语法const/let 对象名new 类名()给对象赋值的语法对象名.属性名值调用对象中的方法对象名.方法名()
*/
const s1new Student()
s1.snoXAWNW1001
s1.sname张资源
s1.gender男
s1.education本科
s1.major土木工程
let infos1.introduce()
console.log(info);
console.log(*******************************);
const s2new Student()
s2.snoXAWNW1002
s2.sname李敏
s2.gender女
s2.education本科
s2.major英语
console.log(s2.introduce());
案例2构造方法的使用
class Student{constructor(sno,sname,gender,education,major){this.snosnothis.snamesnamethis.gendergenderthis.educationeducationthis.majormajor}introduce(){return 学号:${this.sno}\n姓名:${this.sname}\n性别:${this.gender}\n学历:${this.education}\n专业:${this.major}}
}
/*实例化对象的同时进行初始化let/const 对象名new 类名(实参1实参1,....,实参n)*/
const s1new Student(WNXAK1001,何新雨,男,专科,通讯工程)
console.log(s1.introduce());
console.log(*********************************************);
const s2new Student(WNXAK1002,李乐,男,专科,英语)
console.log(s2.introduce());
案例3类的继承
class Teacher{constructor(name,school){this.namenamethis.schoolschool}introduce(){return 我是${this.school}的${this.name}}giveLession(){console.log(讲解本章目标);console.log(讲解本章内容);console.log(进行本章总结);console.log(安排今日作业);}
}
/*** 定义一个子类* 继承的语法* class 子类的名称 extends 父类名称{* }* super关键字的使用* suepr()直接调用父类的构造方法,它的位置必须放在子类构造方法的首行* super.父类中的方法/父类中的属性* 方法的重写:是在继承关系中子类中的方法名和父类中的方法名参数个数相同的这么一种情况称为方法的重写* 方法重写的结果就是子类中的内容完全覆盖父类中方法中的内容*/
class WebTeacher extends Teacher{constructor(name,school){super(name,school)}giveLession(){console.log(首先打开vscode开发环境);super.giveLession()}
}
class TestTeacher extends Teacher{constructor(name,school){super(name,school)}giveLession(){console.log(打开postman或者vm虚拟机);super.giveLession()}
}
let zhaijizhenew WebTeacher(吉,学苑)
console.log(zhaijizhe.introduce());
zhaijizhe.giveLession()
console.log(********************************);
let xuhaidongnew WebTeacher(东,学苑)
console.log(xuhaidong.introduce());
xuhaidong.giveLession()
console.log(**************************************);
const wangxiaofengnew TestTeacher(峰,学苑)
console.log(wangxiaofeng.introduce())
wangxiaofeng.giveLession()
2、定义类组件
类组件是指通过ES6类来定义的组件称为类组件React中定义类组件有如下约定 类名首字母大写 类组件必须要继承React.Component父类这个父类中的相关的方法和属性就能被继承下来 类组件中必须要有一个render方法 这个render必须要要有返回值返回值的内容就是这个类组件的结构jsx 由于这个类组件要被别的组件引用所以使用ES6的默认导出将其导出便于别的组件引用
import React from react
export default class Hello extends React.Component{render(){return(h1Hello组件/h1/) }
}
类组件定义之后引入这个类组件
import ReactDOM from react-dom/client
import Hello from ./components/Hello
const template(Hello/Hello
/)
const rootReactDOM.createRoot(document.querySelector(#root))
root.render(template)
3、定义函数组件【后面重点讲】
在React中除了定义类组件之外也可以定义函数组件
函数组件所谓函数组件是指通过普通函数或者箭头函数所定义出来的组件称为函数组件
函数组件有如下规定 函数名必须首字母大写 使用ES6的export将其默认导出便于别的组件引用 函数必须要有一个返回值这个返回的内容是JSX,返回的是该函数组件的结构
export default function HelloWorld(){return (h1Hello World函数组件/h1/)
}
注意如果不返回任何内容假设返回一个null页面将没有任何内容
在实际开发过程中由于这些类组件和函数组件它的结构都是固定的所以可以使用一些插件将其生成出来 使用rcc生成类组件使用rfc生成函数组件
三、React的事件处理
1、React的事件处理
在React中通过onXx属性来实现单击事件的绑定的常见的写法有四种 直接在标签中通过onClick{(){}}来实现事件绑定 在标签中通过onClick{this.类中的普通的成员方法}的方式来进行绑定 在标签中通过onClick{this.类中的箭头函数}的方式绑定 在标签中通过onClikc{(){this.函数名称()}}
import React, { Component } from reactexport default class Hello extends Component {/*不要使用这种方法*/handleClick(){console.log(类中定义普通方法,this);}handleClick2(){console.log(类中定义的箭头函数,this);}render() {return (button onClick{(){console.log(我是按钮1我被点击了~~~~);}}按钮1/buttonbutton onClick{this.handleClick}按钮2/buttonbutton onClick{this.handleClick2}按钮3/buttonbutton onClick{(){this.handleClick2()}}按钮4/button/)}
}
2、this指向的回顾
let teacher{name:teacher
}
let student{name:student
}
let person{name:person,show(age,sex){return 我叫${this.name},今年${age}岁,我的性别是${sex}}
}
console.log(person.show(38,男))
//改变this指向,改变this执行的方式有三个第一个是call,call的作用调用函数还可以改变this执行
console.log(person.show.call(teacher,48,女));
//通过apply的方式也可以调用函数,这种方式调用方法同时改变this指向
console.log(person.show.apply(student,[22,男]));
//通过bind的方式来改变this指向
let teaherShowperson.show.bind(teacher)
console.log(teaherShow(55,男));
如果使用第二方式来进行事件绑定的时候会存在this执行为空的情况解决办法如下 使用箭头函数写法代替普通方法(建议) 通过bind方式来改变this执行不建议
this执行改变的代码可以写在多个位置比如写在构造函数中经典的写法
export default class Hello extends Component {constructor(){super()//改变this执行this.handleClickthis.handleClick.bind(this)}
}
也可以在调用的同时去改变this指向(不建议) button onClick{this.handleClick.bind(this)}按钮2/button
3、事件传参
import React, { Component } from react
/*React的事件传值的形式有如下三种1、进行事件传值的时候没有实参默认形参接收的event对象2、进行事件调用的同时传递额外的参数
*/
export default class Hello extends Component {handleClick(e){console.log(e,e);}handleClick2(arg1,arg2,arg3){console.log(参数1:,arg1);console.log(参数2:,arg2);console.log(参数3:,arg3);}handleClick3(arg1,arg2,arg3,arg4){console.log(参数1:,arg1);console.log(参数2:,arg2);console.log(参数3:,arg3);console.log(参数4:,arg4);}render() {return (button onClick{this.handleClick}按钮1/buttonbutton onClick{(){this.handleClick2(22,33,56)}}按钮2/buttonbutton onClick{(e){this.handleClick3(89,e,99,78)}}按钮3/button/)}
}
4、合成事件的原理
4.1、底层实现原理
div onClick{this.handleClick.bind(this)}点我/div
React并不是将click事件绑定到了div的真实DOM上 在React16版本中是在document处 监听了所有的事件当事件发⽣并且冒泡到document处的时候React将事 件内容封装并交由真正的处理函数运⾏。 在React17版本中是在根容器(#root)处 监听了所有的事件当事件发⽣并且冒泡到根容器处的时候React将事 件内容封装并交由真正的处理函数运⾏。
这样的⽅式不仅仅减少了内存的消 耗还能在组件挂载销毁时统⼀订阅和移除事件。 除此之外冒泡到document上的事件也不是原⽣的浏览器事件⽽是由 react⾃⼰实现的合成事件SyntheticEvent。
实现合成事件的⽬的如下 合成事件⾸先抹平了浏览器之间的兼容问题另外这是⼀个跨浏览器原⽣ 事件包装器赋予了跨浏览器开发的能⼒ 对于原⽣浏览器事件来说浏览器会给监听器创建⼀个事件对象。如果你 有很多的事件监听那么就需要分配很多的事件对象造成⾼额的内存分 配问题。但是对于合成事件来说有⼀个事件池专⻔来管理它们的创建和 销毁当事件需要被使⽤时就会从池⼦中复⽤对象事件回调结束后 就会销毁事件对象上的属性从⽽便于下次复⽤事件对象。
4.2、 React的事件和普通的HTML事件有什么不同
区别 对于事件名称命名⽅式原⽣事件为全⼩写react 事件采⽤⼩驼峰 对于事件函数处理语法原⽣事件为字符串react 事件为函数 react 事件不能采⽤ return false 的⽅式来阻⽌浏览器的默认⾏为⽽必须要地明确地调⽤preventDefault()来阻⽌默认⾏为。
合成事件是 react 模拟原⽣ DOM 事件所有能⼒的⼀个事件对象其优点如 下 兼容所有浏览器更好的跨平台 将事件统⼀存放在⼀个数组避免频繁的新增与删除垃圾回收。 ⽅便 react 统⼀管理和事务机制。
事件的执⾏顺序为原⽣事件先执⾏合成事件后执⾏合成事件会冒泡绑定到 document 上所以尽量避免原⽣事件与合成事件混⽤如果原⽣事件阻⽌冒 泡可能会导致合成事件不执⾏因为需要冒泡到document 上合成事件才会 执⾏。
四、类组件的state
vue框架和React框架最大的一个好处就是不需要开发人员去操作DOM只要大家操作了数据自动DOM元素会发生变化这种操作称为响应式d
在vue中响应式数据主要来自两个部分 组件内部的响应式数据是定义在data选项 来子组件外部的是通过props来完成定义的
在React中也是一样如果要定义响应式数据组件内部的数据是定义在组件的state中组件外部的数据是定义在props中
1、有状态组件和无状态组件
类组件是有状态组件因为一个组件的状态是存放在类的实例上state,props都是存在this上所以类组件被称为有状态组件
函数组件是无状态组件:函数组件都没有this,函数是不能存放状态的
类组件比较强大函数组件比较单一之前类组件可以完成复杂的功能但是函数组件是简单的组件
在React16.8版本之后引入hooks可以让函数组件也能操作状态、
总结React16.8之前函数组件是无状态组件几乎很少用
2、基本使用步骤
使用state定义数据一共有三步骤
第一步定义数据
定义数据可以在构造函数内部定义也可以在构造函数外部定义
第二步获取数据
在使用数据的时候为了提高读取性能最好使用解构赋值方式
第三步修改数据
修改数据的时候一定要使用setState({})来修改数据这个方法是一个异步方法
第1步、定义数据 定义数据的时候可以在构造函数中定义数据如下所示
class Counter extends React.Component{constructor(){super();this.state{count:0}}render(){return (divh2计数器/h2/div)}
}
export default Counter; 也可以在构造函数外部定义,这种是利用ES6属性的简化语法如下所示
class Counter extends React.Component{//简化语法state{count:0}render(){return (divh2计数器/h2/div)}
}
export default Counter;
第2步、获取数据
通过this.state获取数据
class Counter extends React.Component{constructor(){super();this.state{count:0}}render(){return (divh2计数器/h2span{this.state.count}/span/div)}
}
export default Counter;
在使用数据的时候最好使用解构赋值的方式这样能够提高性能
import React, { Component } from reactexport default class Counter extends Component {state {num: 0}constructor() {super()}render() {const { num } this.state;return (divh1计数器/h1span{num}/span/div)}
}
第3步、修改数据 状态是可以改变的 语法this.setState({要修改的数据}) 注意不要直接修改state中的值这样是错误的 setState()作用1.修改state 2.更新UI
import React, { Component } from reactexport default class Counter extends Component {state {num: 0}constructor() {super()}render() {const { num } this.state;return (divh1计数器/h1span{num}/spanbutton onClick{() {this.setState({num: this.state.num 1})}}1/button/div)}
}
3、购物车案例
实现步骤 在compotents下创建ShopcartList.jsx并在App.jsx中引入这个自定义组件 ShopcartList.jsx中的关键代码如下
import React, { Component } from react
import ../assets/css/shopcartList.scssexport default class ShopcartList extends Component {constructor() {super()//定义状态数据this.state {shopcartList: [{pid: 1001,pname: 欧莱雅男士护肤,price: 38,num: 1},{pid: 1002,pname: OLAY女士防皱润肤露,price: 108,num: 1},{pid: 1003,pname: 自然堂女士护肤,price: 108,num: 2},{pid: 1004,pname: 兰蔻香水,price: 1038,num: 1},{pid: 1005,pname: 大宝SOD,每个人选择,price: 8,num: 1}]}}//改变数量的方法changeNum (sign, index) {switch (sign) {case ://如下这个操作它只能将数据进行更新页面没有进行变化this.state.shopcartList[index].numbreakcase -:if (this.state.shopcartList[index].num 1) {this.state.shopcartList[index].num--} else {window.alert(数量不能少于0)}break}this.setState({shopcartList: this.state.shopcartList})}//计算总价的函数total ary ${ary.reduce((pre, cur) pre cur.price * cur.num, 0).toFixed(2)}//删除方法deleteShopcartList index {if (window.confirm(您确定要删除吗?)) {//数组中的splice方法的参数的含义//第一参数表示要操作数组的下标//第二个参数:表示的是要删除几个数据this.state.shopcartList.splice(index, 1)//使用this.setState来页面this.setState({shopcartList: this.state.shopcartList})}}render() {const { shopcartList } this.statereturn (divh2购物车/h2tabletheadtrtd序号/tdtd名称/tdtd价格/tdtd数量/tdtd小计/tdtd操作/td/tr/theadtbody{shopcartList.map((item, index) tr key{item.pid}td{item.pid}/tdtd{item.pname}/tdtd{item.price}/tdtdbutton classNameoperbtn onClick{() { this.changeNum(-, index) }}-/button{item.num}button classNameoperbtn onClick{() { this.changeNum(, index) }}/button/tdtd{item.price * item.num}/tdtdbutton classNamedelBtn onClick{() { this.deleteShopcartList(index) }}删除/button/td/tr)}/tbodytfoottrtd colSpan{6}{this.total(shopcartList)}/td/tr/tfoot/table/div)}
}
4、setState同步还是异步
setState是同步还是异步的 React18之后setState是异步的如果是React18之前setState根据情况来决定可能是同步的也可以能是异步的 React18版本之后的 在React的事件处理中(合成事件)setState是异步的 在setTimeout、setInterval、原生js中它也是异步的(重点区别) 如果要在react18版本中将this.setState由异步变成同步需要使用flushSync
componentDidMount() {console.log(1、, this.state.count);document.querySelector(#btn).addEventListener(click, () {flushSync((){{this.setState({count: this.state.count 1})console.log(2、, this.state.count);}})flushSync((){this.setState({count: this.state.count 1})console.log(3、, this.state.count);})})} React18版本之前 在React的事件处理中(合成事件)setState是异步的 在setTimeout、setInterval、原生js中它也是同步的
5、setState的另外一种写法
setState((state,props){},(){})