React组件-类组件
组件是什么?
通俗来讲,组件可以被理解为可以被组合的零部件。组件也就是用户界面当中的一块独立区域,在组建每部包含这块区域中的视图、样式、以及逻辑代码
组件有什么用?
组件有两个主要点:复用和解耦
复用:可以用来封装用户界面的重复区块,避免代码重复出现
解耦:一个页面有许多组件,组件与组件之间的代码不会像所有代码堆杂在一块,避免发生代码冲突。
一. 如何 创建组件
// src/App.js
import React from "react";
class App extends React.Component{
render(
retrun <div>根组件</div>;
)
}
export default App;
// src/index.js
import ReactDom from "react-dom/client";
import App from "./App";
const root = ReactDom.createRoot(document.getElementById("root"));
root.render(<APP/>)
二. 组件级样式
组件级样式是什么?
组件级样式是指 样式只在当前组件中生效,当前组件中应用的样式不会溢出到组件的外部从而使得这些样式影响到别的组件,避免了组件样式冲突
组件级样式是怎样实现的?
React中组件级样式依赖webpack提供的css模块功能来实现的,因为在构建的过程中,webpack会为当前组件使用的类名进行重命名,并且在重命名时将类名变为组件+原始类名+随机字符串的结构。所以组件级样式不会溢出影响到外部的组件
三. 组件状态概述
组件状态概述是什么
由于组件是用来构建用户界面的,所以组件状态就是构建的用户界面的状态。
用户状态表示的是在不同条件或不同时间下,为用户展示的用户界面不同。
一般来说,用户界面状态也就是组件状态的状态有 **空闲、加载中、加载成功、加载失败、结束 ** 几种
状态 | 解释 |
---|---|
空闲 | 在没有发出请求时该区域为空闲状态 |
加载中 | 请求在发出后没有得到响应前该区域为加载中状态 |
加载成功 | 当请求得到响应用户列表渲染成功后该区域为成功状态 |
加载失败 | 当请求未得到正确的响应时该区域为失败状态 |
结束 | 不论请求成功与失败请求都结束了该区域为结束状态 |
一般我们可以通过声明变量在程序中进行状态的记录
// idle: 空闲状态
// loading: 加载中
// success: 加载成功
// error: 加载失败
// finish: 结束
let status = "idle";
四. 声明组件状态
在类组件中,组件状态被储存在于state类属性中,这个属性值的类型为对象类型,所以对象中的属性就是组件状态
下面将实现一个简单的计数器来讲解组件的声明、获取和修改
class App extends React.Component{
state ={
count:0
};
}
五. 获取组件状态
首先我们可以知道 render 方法中的 this 指向的是组件的实例对象 , 并且state属性是类的实例属性 , 所以我们可以通过this来获取到state对象
class App extends React.Component{
render(){
return <button>{this.state.count}</button>
}
}
六. 修改组件状态
想要修改类组件中的组件状态,就必须通过类实例对象下面的setState方法进行修改,利用setState方法来接受新的状态作为参数。 然而当前组件实例下是没有setState方法的,setState方法是父类Component提供的
class App extends React.Component{
render(){
return(
<button onClick = {()=> this.setState({count:this,state.count+1})}>button</button>
)
}
}
组件状态发生改变会触发视图自动更新,所以点击按钮后我们可以看到状态的实时变化
七. 状态不可变理念
React中的状态在更新组件状态的时候不能直接操作现有状态,而是要基于现有状态值产生新的状态值
为什么React状态不可变?
因为在React更新真实DOM对象之前,要对新旧状态进行对比找出要更新的部分,所以当前状态不可变
state = {
count:0,
list:[1,2,3],
person:{
name:"张三",
age:20
},
};
用法:
this.setState({
count:this.state.count+1,
list:[...this.state.list,4],
person:{
...this.state.person,
age:23,
},
});
删除:
this.setState({
list:[...this.state.list.slice(0,1),...this.state.list.slice(2)]
});
修改:
this.setState({
list:[...this.state.list.clice(0,1),4,...this.state.list.slice(2)]
})
八. 类组件方法中的this
在之前我们了解到关键字this在JS的事件处理函数中是谁调用指向谁,在JSX元素事件处理函数中指向undefined。
事实上,在类组件中render 、 constructor方法中的this关键字指向当前类的实例对象,而在类组件中元素事件处理函数中依旧指向undefined
在普遍情况下,我们都是希望事件处理函数中this能够指向组建的实例对象,因为只有这样我们才能在更改组件状态时才能调用setState方法
因为我们需要this指向实例对象而不是undefined,所以我们可以更改this指向
class App extends Component{
onClickHandler(){
console.log(this)
}
render(){
return <button onClick = {()=>this.onClickHandler()}>button</button>
}
}
- 将事件处理函数改写为箭头函数,this的指向会更改,指向当前实例
class App extends Component{
onClickHandler = () =>{
console.log(this);
}
render(){
return<button onClick={this.onClickHandler}>button</button>
}
}
为什么改为箭头函数,this就会指向实例对象呢?
因为箭头函数本身不绑定this,当函数被调用后,函数内部的this实际上是constructor构造函数中的this,又因为constructor方法中的this指向当前类的实例对象,所以箭头函数里的this就指向了实例对象
2. 通过bind方法将事件处理函数中的this指向实例对象
class App extends Component{
onClickHandler(){
console.log(this)
}
render(){
return <button onClick={this.onClickHandler.bind(this)}>button</button>
}
}
bind方法返回一个新的被更改了this指向的函数作为事件处理函数,但是每次render重新执行都会为元素绑定新的bind方法返回函数,这样就会给性能造成的一点点影响
- 在构造函数中将事件处理函数更改为组件对象
class App extends Component{
constructor(){
super();
this.onClickHandler = this.onClickHandler.bind(this);
}
onClickHandler(){
console.log(this)
}
render(){
return<button onClick={this.onClickHandler}>button</button>
}
}
因为构造函数中的this指向的就是组件实例对象,所以更改为组件对象的方式保证了事件处理函数的原型方法,又保证this的指向只执行一次,所以从性能角度考虑最为理想
九. 非受控表单
非受控表单就是用户在表单输入的内容由表单自身管理
如果要获取表单控件的值,就要先手动获取表单元素,再通过DOM获取表单值
通过React提供的方法获取DOM对象
import {Component,createRef } from "react"
class App extends Component{
constructor(){
super();
this.onClickHandler = this.onClickHandler.bind(this);
}
inputRef = createRef();
onClickHandler(){
console.log(this.inputRef.current.value);
}
render(){
return(
<>
{/* 为元素引用对象绑定元素 */}
<input type="text" ref={this.inputRef} />
{/* 点击按钮时获取文本框控件自身管理的状态 */}
<button onClick={this.onClickHandler}>button</button>
</>
)
}
}
十. 受控表单
什么是受控表单
受控表单就是用户在表单内输入的内容由组件管理
受控表单不需要自己手动获取,用户在输入内容时,给内容会被实时同步给组件状态,开发者想要获取用户在表单中输入的内容只需要获取组件状态就可以了
受控表单如何实现
- 使用表单控件的value属性将组件状态和表单控件进行绑定
- 使用表单控件onChange事件实现表单控件值和组件状态进行同步
class App extends Component{
state = {
text:"默认值",
};
onChangeHandler = (event) =>{
this.setState({
text:event.target.value,
});
}
render(){
return(
<input type="text" value={this.state.text} onChange={this.onChangeHandler}></input>
)
}
}
当表单控件中只有value属性,而没有onChange事件的情况下,控制台会报警告,因为没有onChange事件的话,将渲染一个只读属性的控件,是无法输入的。所以,使用了value属性的同时也要使用onChange事件
受控表单的执行过程
- 用户出发表单控件的onChange事件,执行事件处理函数
- 在事件处理函数中通过事件对象获取到表单控件的最新状态并使用最新状态更新组件状态
- 组件状态更新完成之后render方法重新执行,在人的人方法中通过最新组件状态渲染视图