大白话React第二章深入理解阶段
1. 学习组件生命周期(类组件)
咱们前面已经知道组件就像蛋糕店里的小蛋糕模块,而组件生命周期就好比是一个小蛋糕从制作到卖出去的整个过程。
- 挂载阶段 :这就相当于蛋糕开始制作,把各种原料准备好放到模具里。在 React 里,组件创建并插入到 DOM 中的过程就是挂载阶段。比如
constructor
就像是你准备原料的过程,在这里初始化一些数据;render
就是把原料变成蛋糕的样子,返回要显示的内容;componentDidMount
就好比蛋糕做好了,从烤箱里拿出来放到展示柜上了,这时候可以做一些后续操作,比如去加载一些外部数据。
jsx
import React, { Component } from 'react';
class CakeComponent extends Component {
// 准备原料,初始化数据
constructor(props) {
super(props);
console.log('开始准备蛋糕原料');
this.state = {
flavor: '巧克力'
};
}
// 把原料变成蛋糕的样子
render() {
console.log('正在制作蛋糕,确定外观');
return (
<div>
<p>这是一个 {this.state.flavor} 口味的蛋糕</p>
</div>
);
}
// 蛋糕做好放到展示柜了,可以做后续操作
componentDidMount() {
console.log('蛋糕做好啦,放到展示柜咯,可以去宣传一下');
}
}
export default CakeComponent;
- 更新阶段 :这就像是蛋糕在展示柜里,根据顾客的反馈或者新的流行趋势,对蛋糕进行一些修改。当组件的
props
或者state
发生变化时,就会进入更新阶段。componentDidUpdate
就好比修改完蛋糕后,重新调整一下展示的位置,或者再装饰一下。
jsx
import React, { Component } from 'react';
class CakeComponent extends Component {
constructor(props) {
super(props);
this.state = {
flavor: '巧克力'
};
}
changeFlavor = () => {
this.setState({ flavor: '草莓' });
};
render() {
return (
<div>
<p>这是一个 {this.state.flavor} 口味的蛋糕</p>
<button onClick={this.changeFlavor}>换成草莓口味</button>
</div>
);
}
componentDidUpdate(prevProps, prevState) {
if (prevState.flavor!== this.state.flavor) {
console.log('蛋糕口味换啦,重新调整一下展示方式');
}
}
}
export default CakeComponent;
- 卸载阶段 :这就好比蛋糕卖出去了,展示柜里就不需要它了。组件从 DOM 中移除时就是卸载阶段,
componentWillUnmount
就像是把蛋糕从展示柜里拿走,清理一下展示柜的位置。
jsx
import React, { Component } from 'react';
class CakeComponent extends Component {
constructor(props) {
super(props);
this.state = {
flavor: '巧克力'
};
}
render() {
return (
<div>
<p>这是一个 {this.state.flavor} 口味的蛋糕</p>
</div>
);
}
componentWillUnmount() {
console.log('蛋糕卖出去啦,清理一下展示柜位置');
}
}
export default CakeComponent;
2. 掌握 props 和 state
- props :
props
就像是蛋糕店的顾客订单要求。当顾客来买蛋糕时,会告诉店员要什么口味、多大尺寸,这些信息就通过props
传递给制作蛋糕的师傅(组件)。
jsx
// 定义一个蛋糕组件,接收顾客订单要求
import React from 'react';
const Cake = (props) => {
return (
<div>
<p>这是一个 {props.flavor} 口味,{props.size} 寸的蛋糕</p>
</div>
);
};
export default Cake;
// 在另一个组件里使用蛋糕组件,传递订单要求
import React from 'react';
import Cake from './Cake';
const CakeShop = () => {
return (
<div>
<Cake flavor="香草" size="8" />
</div>
);
};
export default CakeShop;
- state :
state
就像是蛋糕师傅自己记录的一些信息,比如蛋糕的剩余数量、今天的销售目标等。这些信息是组件自己管理和维护的,并且可以随时改变。
jsx
import React, { Component } from 'react';
class CakeShop extends Component {
constructor(props) {
super(props);
// 初始化蛋糕剩余数量
this.state = {
cakeCount: 10
};
}
sellCake = () => {
if (this.state.cakeCount > 0) {
// 卖出一个蛋糕,更新剩余数量
this.setState({ cakeCount: this.state.cakeCount - 1 });
}
};
render() {
return (
<div>
<p>当前蛋糕剩余数量: {this.state.cakeCount}</p>
<button onClick={this.sellCake}>卖一个蛋糕</button>
</div>
);
}
}
export default CakeShop;
3. 学习事件处理
事件处理就像是蛋糕店处理顾客的各种请求。顾客可能会点击菜单、下单、询问价格等,我们要对这些操作做出响应。
jsx
import React, { Component } from 'react';
class CakeShop extends Component {
constructor(props) {
super(props);
this.state = {
selectedCake: null
};
}
// 处理顾客选择蛋糕的事件
selectCake = (cakeName) => {
this.setState({ selectedCake: cakeName });
};
render() {
return (
<div>
<h1>蛋糕店菜单</h1>
<ul>
<li onClick={() => this.selectCake('巧克力蛋糕')}>巧克力蛋糕</li>
<li onClick={() => this.selectCake('草莓蛋糕')}>草莓蛋糕</li>
</ul>
{this.state.selectedCake && (
<p>你选择了 {this.state.selectedCake}</p>
)}
</div>
);
}
}
export default CakeShop;
4. 处理表单数据
处理表单数据就像是蛋糕店让顾客填写订单信息,然后把这些信息保存下来。
jsx
import React, { Component } from 'react';
class CakeOrderForm extends Component {
constructor(props) {
super(props);
this.state = {
flavor: '',
size: ''
};
}
// 处理输入框内容变化
handleChange = (e) => {
const { name, value } = e.target;
this.setState({ [name]: value });
};
// 处理表单提交
handleSubmit = (e) => {
e.preventDefault();
console.log('你下单了一个', this.state.size, '寸的', this.state.flavor, '口味蛋糕');
};
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
选择口味:
<input
type="text"
name="flavor"
value={this.state.flavor}
onChange={this.handleChange}
/>
</label>
<br />
<label>
选择尺寸:
<input
type="text"
name="size"
value={this.state.size}
onChange={this.handleChange}
/>
</label>
<br />
<button type="submit">下单</button>
</form>
);
}
}
export default CakeOrderForm;
通过这些内容的学习,你就能更深入地理解 React 组件的工作原理,以及如何处理数据和用户交互啦。
代码示例中的this指向什么?
在 React 的代码示例里,this
这玩意儿有点像一个神奇的"指针",它指向的是当前正在执行操作的那个"东西",在类组件里,主要指向的就是这个类组件的实例,下面我用大白话结合前面的代码示例详细给你说说。
1. 在构造函数 constructor
里的 this
咱们先看之前 CakeComponent
组件的构造函数:
jsx
import React, { Component } from 'react';
class CakeComponent extends Component {
constructor(props) {
super(props);
console.log('开始准备蛋糕原料');
this.state = {
flavor: '巧克力'
};
}
// 其他代码...
}
在这个构造函数里,this
就像是一个"主人牌",它指的就是当前这个 CakeComponent
组件的实例。就好比你开了一家蛋糕店,每个蛋糕就是一个组件实例,this
就是贴在这个蛋糕上的标签,告诉别人这是哪个蛋糕。当你写 this.state = { flavor: '巧克力' };
的时候,就是在说给这个特定的蛋糕贴上"巧克力口味"的标签,把这个口味信息存到这个蛋糕(组件实例)自己的小本本(state
)里。
2. 在自定义方法里的 this
再看看 CakeComponent
里的 changeFlavor
方法:
jsx
class CakeComponent extends Component {
constructor(props) {
super(props);
this.state = {
flavor: '巧克力'
};
}
changeFlavor = () => {
this.setState({ flavor: '草莓' });
};
// 其他代码...
}
这里的 this
同样指向 CakeComponent
组件的实例。changeFlavor
方法就像是一个给蛋糕换口味的小工具,当你用这个工具去操作蛋糕的时候,this
能让你明确知道是在操作哪个蛋糕。this.setState
就是在说,我要给贴了这个"主人牌"(this
)的蛋糕把口味改成草莓味。
不过要注意哦,如果不用箭头函数,而是用普通函数的写法,this
的指向就可能会出问题。比如这样:
jsx
class CakeComponent extends Component {
constructor(props) {
super(props);
this.state = {
flavor: '巧克力'
};
}
changeFlavor() {
this.setState({ flavor: '草莓' });
}
render() {
return (
<div>
<p>这是一个 {this.state.flavor} 口味的蛋糕</p>
<button onClick={this.changeFlavor}>换成草莓口味</button>
</div>
);
}
}
在普通函数里,this
的指向会根据函数的调用方式改变,当你点击按钮调用 changeFlavor
时,this
可能就不是指向组件实例了,这样 this.setState
就会出错。而箭头函数不会自己创建 this
,它会继承外层作用域的 this
,所以用箭头函数就能保证 this
一直指向组件实例。
3. 在生命周期方法里的 this
像 componentDidMount
、componentDidUpdate
这些生命周期方法里的 this
,也是指向组件实例。比如:
jsx
class CakeComponent extends Component {
constructor(props) {
super(props);
this.state = {
flavor: '巧克力'
};
}
componentDidMount() {
console.log('蛋糕做好啦,这个蛋糕的口味是', this.state.flavor);
}
// 其他代码...
}
在 componentDidMount
里,this
还是那个"主人牌",通过 this.state.flavor
就能知道这个蛋糕的口味信息,就像看贴在蛋糕上的标签一样。
总的来说,在 React 的类组件里,this
就像是一个标记,让你能准确地找到当前正在操作的那个组件实例,方便你对这个实例的各种属性(比如 state
)和方法进行操作。
如何在类组件的方法中正确使用 this?
在 React 的类组件方法里正确使用 this
,就好比在一场游戏里准确找到自己的角色,然后用这个角色去完成各种任务。下面我结合之前蛋糕店的例子,用大白话详细跟你说说怎么在类组件方法里正确使用 this
。
1. 构造函数里绑定 this
咱先看看之前做蛋糕的代码例子:
jsx
import React, { Component } from 'react';
class CakeShop extends Component {
constructor(props) {
super(props);
this.state = {
cakeCount: 10
};
// 手动绑定 this
this.sellCake = this.sellCake.bind(this);
}
sellCake() {
if (this.state.cakeCount > 0) {
this.setState({ cakeCount: this.state.cakeCount - 1 });
}
}
render() {
return (
<div>
<p>当前蛋糕剩余数量: {this.state.cakeCount}</p>
<button onClick={this.sellCake}>卖一个蛋糕</button>
</div>
);
}
}
export default CakeShop;
在构造函数 constructor
里,this
指向的是当前这个 CakeShop
组件实例,就好像给这个蛋糕店贴上了一个独一无二的标签。当我们定义了 sellCake
这个方法,它一开始并不知道自己要操作哪个蛋糕店(也就是不知道 this
指向谁)。所以我们用 this.sellCake = this.sellCake.bind(this);
这行代码,就相当于给 sellCake
方法也贴上了和蛋糕店一样的标签,让它知道自己要操作的就是这个特定的蛋糕店。这样在 sellCake
方法里使用 this.state.cakeCount
时,就能准确地访问到这个蛋糕店的蛋糕剩余数量。
2. 使用箭头函数
箭头函数是个很方便的工具,能帮我们避免 this
指向混乱的问题。看下面这个例子:
jsx
import React, { Component } from 'react';
class CakeShop extends Component {
constructor(props) {
super(props);
this.state = {
cakeCount: 10
};
}
// 使用箭头函数定义方法
sellCake = () => {
if (this.state.cakeCount > 0) {
this.setState({ cakeCount: this.state.cakeCount - 1 });
}
};
render() {
return (
<div>
<p>当前蛋糕剩余数量: {this.state.cakeCount}</p>
<button onClick={this.sellCake}>卖一个蛋糕</button>
</div>
);
}
}
export default CakeShop;
箭头函数不会自己创建一个新的 this
,它会直接继承外层作用域的 this
。在这个例子里,sellCake
箭头函数继承的就是 CakeShop
组件实例的 this
,就好像它天生就带着和蛋糕店一样的标签,所以在函数里使用 this.state.cakeCount
时,能直接找到这个蛋糕店的蛋糕剩余数量,不需要我们手动去绑定 this
。
3. 内联箭头函数
有时候我们也会在 JSX 里直接用内联箭头函数来处理事件,比如:
jsx
import React, { Component } from 'react';
class CakeShop extends Component {
constructor(props) {
super(props);
this.state = {
cakeCount: 10
};
}
sellCake() {
if (this.state.cakeCount > 0) {
this.setState({ cakeCount: this.state.cakeCount - 1 });
}
}
render() {
return (
<div>
<p>当前蛋糕剩余数量: {this.state.cakeCount}</p>
<button onClick={() => this.sellCake()}>卖一个蛋糕</button>
</div>
);
}
}
export default CakeShop;
在这个例子里,我们在 onClick
事件里用了内联箭头函数 () => this.sellCake()
。这里的 this
同样是继承自 CakeShop
组件实例。当点击按钮时,箭头函数会调用 sellCake
方法,并且能正确地把 this
传递过去,让 sellCake
方法知道要操作的是哪个蛋糕店。不过要注意,内联箭头函数每次渲染都会创建一个新的函数,可能会对性能有一点影响,所以如果是简单的事件处理,推荐用前面两种方法。
总结一下,要在类组件方法里正确使用 this
,可以在构造函数里手动绑定 this
,或者使用箭头函数让它自动继承外层的 this
,这样就能准确地操作组件实例的各种属性和方法啦。
如何解决在类组件中 this 指向不正确的问题?
在 React 的类组件里,this
指向不正确就好比你在一个大商场里迷路了,找不到自己要去的店铺。不过别担心,有几种办法能帮你解决这个问题,下面我结合之前蛋糕店的例子,用大白话给你详细讲讲。
1. 在构造函数中手动绑定 this
咱们先看之前的 CakeShop
组件代码:
jsx
import React, { Component } from 'react';
class CakeShop extends Component {
constructor(props) {
super(props);
this.state = {
cakeCount: 10
};
// 手动绑定 this
this.sellCake = this.sellCake.bind(this);
}
sellCake() {
if (this.state.cakeCount > 0) {
this.setState({ cakeCount: this.state.cakeCount - 1 });
}
}
render() {
return (
<div>
<p>当前蛋糕剩余数量: {this.state.cakeCount}</p>
<button onClick={this.sellCake}>卖一个蛋糕</button>
</div>
);
}
}
export default CakeShop;
在普通函数(像 sellCake
方法)里,this
的指向会根据函数的调用方式而改变。当我们在 constructor
里写 this.sellCake = this.sellCake.bind(this);
时,就好比给 sellCake
方法发了一张"身份证",上面写着它属于当前这个 CakeShop
组件实例。这样一来,不管 sellCake
方法在哪里被调用,它都知道自己要操作的是哪个蛋糕店,this
就能正确地指向 CakeShop
组件实例,从而能准确地访问 this.state.cakeCount
这个蛋糕剩余数量。
2. 使用箭头函数定义方法
看下面修改后的代码:
jsx
import React, { Component } from 'react';
class CakeShop extends Component {
constructor(props) {
super(props);
this.state = {
cakeCount: 10
};
}
// 使用箭头函数定义方法
sellCake = () => {
if (this.state.cakeCount > 0) {
this.setState({ cakeCount: this.state.cakeCount - 1 });
}
};
render() {
return (
<div>
<p>当前蛋糕剩余数量: {this.state.cakeCount}</p>
<button onClick={this.sellCake}>卖一个蛋糕</button>
</div>
);
}
}
export default CakeShop;
箭头函数就像是一个忠诚的小跟班,它不会自己创建一个新的 this
,而是直接继承它外层作用域的 this
。在这个例子里,sellCake
箭头函数继承的就是 CakeShop
组件实例的 this
。这就好比小跟班一直紧紧跟着主人(组件实例),不管走到哪里,都知道自己的主人是谁。所以在 sellCake
函数里使用 this.state.cakeCount
时,能直接找到这个蛋糕店的蛋糕剩余数量,不会出现 this
指向混乱的问题。
3. 使用内联箭头函数调用方法
再看另一种情况:
jsx
import React, { Component } from 'react';
class CakeShop extends Component {
constructor(props) {
super(props);
this.state = {
cakeCount: 10
};
}
sellCake() {
if (this.state.cakeCount > 0) {
this.setState({ cakeCount: this.state.cakeCount - 1 });
}
}
render() {
return (
<div>
<p>当前蛋糕剩余数量: {this.state.cakeCount}</p>
<button onClick={() => this.sellCake()}>卖一个蛋糕</button>
</div>
);
}
}
export default CakeShop;
这里我们在 onClick
事件里用了内联箭头函数 () => this.sellCake()
。这个内联箭头函数同样会继承它外层作用域(也就是 CakeShop
组件实例)的 this
。当你点击按钮时,箭头函数会去调用 sellCake
方法,并且能把正确的 this
传递给 sellCake
方法。不过要注意,每次组件渲染的时候,内联箭头函数都会重新创建一个新的函数,这可能会对性能有那么一点点影响,所以如果只是简单的事件处理,前面两种方法会更好一些。
总之,要解决类组件中 this
指向不正确的问题,你可以在构造函数里手动绑定 this
,或者使用箭头函数来让它自动继承正确的 this
指向。这样,你在操作组件实例的属性和方法时就不会迷路啦。
除了类组件,函数组件中的 this 指向什么?
在 React 里,除了类组件,还有函数组件。和类组件不太一样,函数组件里可没有 this
这个东西指向特定对象,下面我用大白话给你详细说说为啥是这样。
1. 函数组件就像一个独立小工匠
你可以把函数组件想象成一个独立的小工匠。这个小工匠接到一个制作任务(也就是接收一些数据作为参数),然后专心做出一个成品(返回一段 JSX 代码来展示界面)。它不需要像类组件那样有一个"自己的家"(实例),所以也就不需要 this
来指向自己。
比如下面这个简单的函数组件:
jsx
import React from 'react';
// 定义一个名为 Greeting 的函数组件
const Greeting = (props) => {
return <h1>Hello, {props.name}!</h1>;
};
export default Greeting;
这里的 Greeting
函数组件就像一个小工匠,它接收 props
这个参数,里面包含了要显示的名字信息。然后它直接根据这个信息返回一段显示问候语的 JSX 代码。在整个过程中,它不需要用 this
来表示自己,因为它只是一个单纯的函数,每次调用它,它就按照给定的参数干活,没有自己的状态或者属性需要用 this
去访问。
2. 没有实例就不需要 this
标记
类组件就像一个有自己房子(实例)的大家庭,this
就像是这个大家庭的门牌号,通过这个门牌号可以找到家里的各种东西(属性和方法)。但是函数组件没有这样的房子(实例),它就是一个临时的工作坊,来一个任务就做一个任务,做完就拉倒。所以根本不需要 this
来标记自己。
再看一个稍微复杂点的例子:
jsx
import React from 'react';
const Product = (props) => {
const showDetails = () => {
// 这里不需要 this,直接用 props 里的数据
console.log(`Product name: ${props.name}, Price: ${props.price}`);
};
return (
<div>
<h2>{props.name}</h2>
<p>Price: {props.price}</p>
<button onClick={showDetails}>Show details</button>
</div>
);
};
export default Product;
在 Product
函数组件里,有一个 showDetails
函数用来显示产品的详细信息。在这个函数里,我们直接使用 props
里的数据,而不需要用 this
去访问。因为函数组件没有自己的实例,所有的数据都是通过参数传递进来的,所以不需要 this
来帮忙找东西。
3. 用 Hooks 管理状态也不用 this
后来 React 出了 Hooks,让函数组件也能有自己的状态。但是即使使用了 Hooks,还是不需要 this
。比如用 useState
Hook 来管理状态:
jsx
import React, { useState } from 'react';
const Counter = () => {
// 使用 useState Hook 定义一个状态变量 count 和更新函数 setCount
const [count, setCount] = useState(0);
const increment = () => {
// 直接调用 setCount 来更新状态,不需要 this
setCount(count + 1);
};
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
};
export default Counter;
在 Counter
函数组件里,我们用 useState
定义了一个状态变量 count
和更新函数 setCount
。在 increment
函数里,我们直接调用 setCount
来更新状态,不需要像类组件那样用 this.setState
,因为函数组件没有 this
这个概念。
总之,函数组件就像一个个独立干活的小工匠,它们没有自己的实例,不需要用 this
来指向自己,所有的数据和操作都是通过参数和函数来完成的。
类组件和函数组件有什么区别?
在 React 里,类组件和函数组件就像是两种不同类型的厨师,他们都能做出美食(构建页面),但做菜的方式和特点不太一样。下面我用大白话详细给你说说它们的区别。
1. 定义方式不同
- 类组件 :类组件就像是一个专业的厨师团队,有一套完整的流程和规则。定义类组件的时候,你得创建一个类,这个类要继承自
React.Component
,就好比厨师团队要遵循一套特定的行业规范。在这个类里,你要写很多方法,像render
方法就相当于厨师团队做菜的核心步骤,规定了要做出什么样的菜品(返回什么样的页面结构)。
jsx
import React, { Component } from 'react';
// 定义一个类组件,继承自 React.Component
class CakeShop extends Component {
render() {
return <h1>欢迎来到蛋糕店!</h1>;
}
}
export default CakeShop;
- 函数组件 :函数组件就像是一个独立的厨师,比较随性自由。定义函数组件很简单,就是写一个普通的 JavaScript 函数,这个函数接收一些参数(通常叫
props
),然后返回一段 JSX 代码,就像独立厨师根据客人的要求(参数)做出一道菜(页面结构)。
jsx
import React from 'react';
// 定义一个函数组件
const CakeShop = (props) => {
return <h1>欢迎来到 {props.name} 蛋糕店!</h1>;
};
export default CakeShop;
2. 状态管理不同
- 类组件 :类组件就像是一个有仓库的厨师团队,他们可以在仓库(
state
)里存放各种食材(数据),并且可以随时去仓库拿食材来做菜,也能往仓库里添加或更换食材。在类组件里,你可以在构造函数里初始化state
,然后用this.setState
方法来更新state
。
jsx
import React, { Component } from 'react';
class CakeShop extends Component {
constructor(props) {
super(props);
// 初始化仓库(state)里的食材(数据)
this.state = {
cakeCount: 10
};
}
sellCake = () => {
// 从仓库拿食材(更新 state)
this.setState({ cakeCount: this.state.cakeCount - 1 });
};
render() {
return (
<div>
<p>当前蛋糕剩余数量: {this.state.cakeCount}</p>
<button onClick={this.sellCake}>卖一个蛋糕</button>
</div>
);
}
}
export default CakeShop;
- 函数组件 :在以前,函数组件就像是一个没有仓库的独立厨师,只能根据客人现有的要求(
props
)做菜,没办法自己存放和管理食材(数据)。不过后来 React 出了 Hooks,有了useState
这个工具,函数组件也能有自己的小抽屉(状态)来存放一些简单的食材(数据)了。
jsx
import React, { useState } from 'react';
const CakeShop = () => {
// 创建一个小抽屉(状态),初始放 10 个蛋糕
const [cakeCount, setCakeCount] = useState(10);
const sellCake = () => {
// 从抽屉拿蛋糕(更新状态)
setCakeCount(cakeCount - 1);
};
return (
<div>
<p>当前蛋糕剩余数量: {cakeCount}</p>
<button onClick={sellCake}>卖一个蛋糕</button>
</div>
);
};
export default CakeShop;
3. 生命周期方法不同
- 类组件 :类组件就像是一个按部就班工作的厨师团队,有一套完整的工作流程,从开店准备(挂载阶段),到中间不断调整菜品(更新阶段),再到关店收拾(卸载阶段),每个阶段都有对应的方法可以去执行一些特定的任务。比如
componentDidMount
就像是开店准备好后,开始正式营业,可以去做一些宣传活动(加载数据等)。
jsx
import React, { Component } from 'react';
class CakeShop extends Component {
componentDidMount() {
console.log('蛋糕店开业啦,开始宣传!');
}
render() {
return <h1>欢迎来到蛋糕店!</h1>;
}
}
export default CakeShop;
- 函数组件 :函数组件就像是一个比较随性的独立厨师,没有那么多固定的工作流程。不过有了 Hooks 之后,
useEffect
可以模拟一些生命周期方法的功能。比如在useEffect
里可以做一些类似componentDidMount
的事情。
jsx
import React, { useEffect } from 'react';
const CakeShop = () => {
useEffect(() => {
console.log('蛋糕店开业啦,开始宣传!');
// 这里可以返回一个清理函数,类似 componentWillUnmount
return () => {
console.log('蛋糕店关门啦,收拾东西!');
};
}, []);
return <h1>欢迎来到蛋糕店!</h1>;
};
export default CakeShop;
4. this
的使用不同
- 类组件 :类组件里的
this
就像是厨师团队的队长,通过this
可以指挥团队里的各种资源(属性和方法)。在类组件里,你可以用this
来访问state
、调用方法等。不过要注意this
的指向问题,有时候需要手动绑定。 - 函数组件 :函数组件里没有
this
这个概念,因为它就像一个独立厨师,不需要队长来指挥。所有的数据和操作都是通过参数和函数来完成的。
5. 性能和复杂度不同
- 类组件:类组件相对复杂一些,因为有很多方法和生命周期要管理,就像厨师团队的管理比较麻烦。而且每次状态更新,可能会触发整个组件的重新渲染,性能上可能会有一些损耗。
- 函数组件:函数组件比较简单,代码量通常也比较少,就像独立厨师干活比较简洁。而且 React 对函数组件做了很多优化,性能上可能会更好一些。
总的来说,类组件功能强大,适合处理复杂的逻辑和状态管理;函数组件简洁灵活,适合做一些简单的展示性组件。在实际开发中,可以根据具体的需求来选择使用哪种组件。
如何优化组件的生命周期方法?
在 React 里,组件的生命周期方法就像是一场表演的不同环节,优化这些环节能让表演更精彩,也就是让组件性能更好、运行更流畅。下面咱就用大白话详细说说怎么优化组件的生命周期方法。
1. 挂载阶段优化(componentDidMount
)
componentDidMount
就像是表演开场前的准备工作,这时候要确保只做必要的事情,别做多余的活儿。
- 避免重复请求数据 :假如你要在组件挂载的时候从服务器获取数据,就像开场前要从后台拿道具,只拿一次就行,别来回跑。比如说你做一个新闻列表组件,在
componentDidMount
里发一次请求获取新闻数据,别在这方法里写循环重复发请求,不然服务器会被你折腾坏,页面加载也会变慢。
jsx
import React, { Component } from 'react';
class NewsList extends Component {
constructor(props) {
super(props);
this.state = {
news: []
};
}
componentDidMount() {
// 只发一次请求获取新闻数据
fetch('https://api.example.com/news')
.then(response => response.json())
.then(data => this.setState({ news: data }));
}
render() {
return (
<div>
{this.state.news.map(item => (
<p key={item.id}>{item.title}</p>
))}
</div>
);
}
}
export default NewsList;
- 初始化第三方库:如果要在组件挂载时初始化一些第三方库,像图表库、地图库啥的,确保这些库的初始化代码简洁高效。就好比开场前布置舞台道具,要快速又准确地把道具摆好。
2. 更新阶段优化(shouldComponentUpdate
、componentDidUpdate
)
更新阶段就像是表演过程中根据观众反馈调整表演内容,要聪明地判断要不要调整,别瞎折腾。
- 使用
shouldComponentUpdate
避免不必要的渲染 :shouldComponentUpdate
就像是一个小门卫,能决定要不要让组件重新渲染。在这个方法里,你可以对比props
和state
的新旧值,如果没变化就不让组件重新渲染,省点力气。
jsx
import React, { Component } from 'react';
class Counter extends Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
shouldComponentUpdate(nextProps, nextState) {
// 如果 count 没变化,就不重新渲染
if (this.state.count === nextState.count) {
return false;
}
return true;
}
increment = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={this.increment}>Increment</button>
</div>
);
}
}
export default Counter;
- 在
componentDidUpdate
里避免无限循环 :componentDidUpdate
就像是表演过程中的小调整,但别调整过头了,导致一直调整个没完。比如说你在这个方法里更新state
,要确保有条件限制,别每次更新都触发componentDidUpdate
然后又更新state
,形成无限循环。
jsx
import React, { Component } from 'react';
class Example extends Component {
constructor(props) {
super(props);
this.state = {
value: 0
};
}
componentDidUpdate(prevProps, prevState) {
// 只有当 value 小于 10 时才更新 state
if (prevState.value < 10) {
this.setState({ value: prevState.value + 1 });
}
}
render() {
return <p>Value: {this.state.value}</p>;
}
}
export default Example;
3. 卸载阶段优化(componentWillUnmount
)
componentWillUnmount
就像是表演结束后收拾舞台,要把该清理的东西都清理干净,别留下垃圾。
- 清除定时器和事件监听器 :如果你在组件里用了定时器,像
setInterval
或者setTimeout
,在组件卸载的时候要清除它们,不然它们会一直在后台运行,浪费资源。还有事件监听器,比如给窗口添加的滚动监听,组件卸载时也要移除,不然可能会导致一些奇怪的问题。
jsx
import React, { Component } from 'react';
class TimerComponent extends Component {
constructor(props) {
super(props);
this.state = {
seconds: 0
};
this.timer = null;
}
componentDidMount() {
this.timer = setInterval(() => {
this.setState({ seconds: this.state.seconds + 1 });
}, 1000);
}
componentWillUnmount() {
// 清除定时器
clearInterval(this.timer);
}
render() {
return <p>Seconds passed: {this.state.seconds}</p>;
}
}
export default TimerComponent;
通过这些优化方法,能让组件的生命周期方法更高效,让你的 React 应用跑得又快又稳,就像一场精彩又流畅的表演一样。