【react】react 生命周期

react 生命周期

相关文章

react 生命周期


一、挂载阶段

constructor()

组件的构造函数,在创建组件实例时调用。用于初始化状态和绑定事件处理函数。

类组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import React, { Component } from 'react';

class MyComponent extends Component {
constructor(props) {
super(props);
// 在构造函数中初始化状态
this.state = {
count: 0
};
// 在构造函数中绑定事件处理函数
this.handleClick = this.handleClick.bind(this);
}

// 事件处理函数
handleClick() {
this.setState((prevState) => ({
count: prevState.count + 1
}));
}

render() {
return (
<div>
<p>Count: {this.state.count}</p>
{/* 绑定事件处理函数 */}
<button onClick={this.handleClick}>Increment</button>
</div>
);
}
}

export default MyComponent;

函数组件模拟

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import React, { useState, useEffect } from 'react';

function MyComponent() {
// 使用 useState 初始化状态
const [count, setCount] = useState(0);

// 事件处理函数
const handleClick = () => {
setCount(prevCount => prevCount + 1);
};

// 渲染 JSX
return (
<div>
<p>Count: {count}</p>
{/* 绑定事件处理函数 */}
<button onClick={handleClick}>Increment</button>
</div>
);
}

export default MyComponent;

在这个示例中,我们使用 useState 来初始化状态 count。

static getDerivedStateFromProps(props, state):

在组件挂载之前调用,用于根据 props 来更新 state。它返回一个对象来更新 state,或者返回 null 表示不需要更新 state。

类组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import React, { Component } from 'react';

class MyComponent extends Component {
state = {
value: ''
};

static getDerivedStateFromProps(nextProps, prevState) {
// 如果 props 中的 value 发生了变化,则更新 state
if (nextProps.value !== prevState.value) {
return {
value: nextProps.value
};
}
// 否则返回 null 表示不需要更新 state
return null;
}

render() {
return (
<div>
<p>Value: {this.state.value}</p>
</div>
);
}
}

// 使用示例
class App extends Component {
state = {
inputValue: ''
};

handleChange = (e) => {
this.setState({
inputValue: e.target.value
});
};

render() {
return (
<div>
<input
type="text"
value={this.state.inputValue}
onChange={this.handleChange}
/>
{/* 将输入框的值作为 props 传递给 MyComponent */}
<MyComponent value={this.state.inputValue} />
</div>
);
}
}

export default App;

在这个示例中,MyComponent 组件接收一个名为 value 的 prop,当 value 发生变化时,我们希望组件的内部状态也跟着更新。通过 getDerivedStateFromProps 方法,我们可以在组件每次渲染之前检查 value 是否发生变化,如果发生变化则更新组件的 state。

函数组件模拟

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import React, { useState, useEffect } from 'react';

function MyComponent({ value }) {
const [state, setState] = useState('');

useEffect(() => {
setState(value);
}, [value]);

return (
<div>
<p>Value: {state}</p>
</div>
);
}

// 使用示例
function App() {
const [inputValue, setInputValue] = useState('');

const handleChange = (e) => {
setInputValue(e.target.value);
};

return (
<div>
<input
type="text"
value={inputValue}
onChange={handleChange}
/>
{/* 将输入框的值作为 props 传递给 MyComponent */}
<MyComponent value={inputValue} />
</div>
);
}

export default App;

这个示例中,我们使用 useState 来创建状态,并在 useEffect 中监听 value 的变化,从而更新组件的内部状态。这样,就模拟了 getDerivedStateFromProps 的功能。

render()

渲染方法,用于生成组件的 JSX 结构。

类组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import React, { Component } from 'react';

class Counter extends Component {
constructor(props) {
super(props);
// 初始化状态
this.state = {
count: 0
};
}

// 增加计数器的方法
increment = () => {
this.setState((prevState) => ({
count: prevState.count + 1
}));
};

// 渲染组件的方法
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={this.increment}>Increment</button>
</div>
);
}
}

export default Counter;

函数组件模拟

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import React, { useState } from 'react';

function Counter() {
// 使用 useState 来定义状态
const [count, setCount] = useState(0);

// 定义增加计数器的方法
const increment = () => {
setCount(count + 1);
};

// 渲染函数式组件的返回值
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
}

export default Counter;

在函数式组件中,render 方法被替代为组件本身的返回值。

componentDidMount()

在组件挂载之后调用,可以进行 DOM 操作、数据获取等副作用操作。

类组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import React, { Component } from 'react';

class MyComponent extends Component {
componentDidMount() {
console.log('Component mounted');
// 在组件挂载后执行一些操作,比如数据获取等
}

render() {
return (
<div>
<p>My Component</p>
</div>
);
}
}

export default MyComponent;

函数组件模拟

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import React, { useEffect } from 'react';

function MyComponent() {
useEffect(() => {
console.log('Component mounted');
// 在组件挂载后执行一些操作,比如数据获取等
}, []); // 传入空数组表示只在组件挂载时执行一次

return (
<div>
<p>My Component</p>
</div>
);
}

export default MyComponent;

在这个示例中,我们使用 useEffect 钩子函数来模拟 componentDidMount 方法的功能。传入空数组作为第二个参数,表示 useEffect 仅在组件挂载时执行一次。

二、更新阶段

static getDerivedStateFromProps(props, state)

(同上)在更新阶段调用,用于根据 props 更新 state。

shouldComponentUpdate(nextProps, nextState)

在组件接收到新的 props 或 state 时调用,用于判断是否需要重新渲染组件。默认返回 true,表示组件总是会重新渲染。可以通过手动比较 props 和 state 来优化性能。

类组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import React, { Component } from 'react';

class MyComponent extends Component {
// 控制组件是否重新渲染的方法
shouldComponentUpdate(nextProps, nextState) {
// 如果 props 或 state 发生变化,则重新渲染组件
if (nextProps.someProp !== this.props.someProp || nextState.someState !== this.state.someState) {
return true;
}
// 否则不重新渲染组件
return false;
}

render() {
return (
<div>
<p>{this.props.someProp}</p>
</div>
);
}
}

export default MyComponent;

函数组件模拟

1
2
3
4
5
6
7
8
9
10
11
import React from 'react';

function MyComponent({ someProp }) {
return (
<div>
<p>{someProp}</p>
</div>
);
}

export default React.memo(MyComponent);

在这个示例中,我们使用 React.memo 高阶组件来包装函数式组件 MyComponent,以达到控制组件是否重新渲染的目的。React.memo 会对组件的 props 进行浅比较,如果 props 没有变化,则不重新渲染组件。

render()

(同上)渲染方法,用于生成组件的 JSX 结构。

getSnapshotBeforeUpdate(prevProps, prevState)

在最近一次渲染输出(提交到 DOM 上)之前调用,用于获取更新前的 DOM 状态。它的返回值将作为第三个参数传递给 componentDidUpdate 方法。

类组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import React, { Component } from 'react';

class MyComponent extends Component {
constructor(props) {
super(props);
this.state = {
isVisible: true
};
this.buttonRef = React.createRef();
}

componentDidMount() {
// 模拟每秒钟切换一次按钮的显示状态
setTimeout(() => {
this.setState(prevState => ({
isVisible: !prevState.isVisible
}));
}, 1000);
}

getSnapshotBeforeUpdate(prevProps, prevState) {
// 获取更新前的按钮可见状态
return prevState.isVisible;
}

componentDidUpdate(prevProps, prevState, snapshot) {
// 根据快照值判断按钮可见状态是否发生变化,并在控制台打印相应的信息
if (this.state.isVisible !== snapshot) {
console.log('Button visibility changed!');
}
}

render() {
return (
<div>
{this.state.isVisible && (
<button ref={this.buttonRef}>Click me</button>
)}
</div>
);
}
}

export default MyComponent;

在这个示例中,MyComponent 组件每秒钟切换一次按钮的显示状态,getSnapshotBeforeUpdate 方法用于获取更新前的按钮可见状态,然后在 componentDidUpdate 方法中根据快照值判断按钮可见状态是否发生变化,并在控制台打印相应的信息。

函数组件模拟

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import React, { useState, useEffect, useRef } from 'react';

function MyComponent() {
const [isVisible, setIsVisible] = useState(true);
const buttonRef = useRef(null);
const prevIsVisibleRef = useRef(null);

useEffect(() => {
// 模拟每秒钟切换一次按钮的显示状态
const intervalId = setInterval(() => {
setIsVisible(prev => !prev);
}, 1000);

return () => clearInterval(intervalId);
}, []);

useEffect(() => {
prevIsVisibleRef.current = isVisible;
}, [isVisible]);

useEffect(() => {
// 获取更新前的按钮可见状态
const prevIsVisible = prevIsVisibleRef.current;
// 根据快照值判断按钮可见状态是否发生变化,并在控制台打印相应的信息
if (prevIsVisible !== null && isVisible !== prevIsVisible) {
console.log('Button visibility changed!');
}
});

return (
<div>
{isVisible && (
<button ref={buttonRef}>Click me</button>
)}
</div>
);
}

export default MyComponent;

在这个函数式组件中,我们使用了 useState 来管理按钮的可见状态,使用 useRef 来保存上一个可见状态的值,以便在更新后比较前后状态的变化。然后,我们使用两个 useEffect 钩子函数,一个用于模拟每秒钟切换按钮的显示状态,另一个用于获取更新前的状态并判断是否发生变化。

componentDidUpdate(prevProps, prevState, snapshot)

在组件更新(重新渲染)之后调用,可以进行 DOM 操作、数据更新等副作用操作。

类组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import React, { Component } from 'react';

class MyComponent extends Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}

componentDidUpdate(prevProps, prevState) {
// 检查前后 props 的变化
if (prevProps.userId !== this.props.userId) {
// 根据新的 props 更新组件状态
this.setState({ count: 0 });
}
}

render() {
return (
<div>
<p>User ID: {this.props.userId}</p>
<p>Count: {this.state.count}</p>
<button onClick={() => this.setState(prevState => ({ count: prevState.count + 1 }))}>
Increment
</button>
</div>
);
}
}

export default MyComponent;

在这个示例中,MyComponent 组件每秒钟切换一次按钮的显示状态,getSnapshotBeforeUpdate 方法用于获取更新前的按钮可见状态,然后在 componentDidUpdate 方法中根据快照值判断按钮可见状态是否发生变化,并在控制台打印相应的信息。

函数组件模拟

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import React, { useState, useEffect } from 'react';

function MyComponent({ userId }) {
const [count, setCount] = useState(0);

// 模拟 componentDidUpdate
useEffect(() => {
// 在组件更新后执行的操作
console.log('Component updated!');
// 检查前后 props 的变化
// 这里假设你想要在 userId 发生变化时重置 count
setCount(0);
}, [userId]); // 只有 userId 发生变化时才执行

return (
<div>
<p>User ID: {userId}</p>
<p>Count: {count}</p>
<button onClick={() => setCount(prevCount => prevCount + 1)}>
Increment
</button>
</div>
);
}

export default MyComponent;

在这个示例中,我们使用 useEffect 钩子函数来模拟 componentDidUpdate。

三、卸载阶段

componentWillUnmount()

在组件卸载(销毁)之前调用,用于清理定时器、取消订阅等资源释放操作。

类组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import React, { Component } from 'react';

class Timer extends Component {
constructor(props) {
super(props);
this.state = {
seconds: 0
};
}

componentDidMount() {
this.intervalId = setInterval(() => {
this.setState(prevState => ({
seconds: prevState.seconds + 1
}));
}, 1000);
}

componentWillUnmount() {
clearInterval(this.intervalId); // 在组件即将卸载时清除定时器
}

render() {
return (
<div>
<p>Timer: {this.state.seconds} seconds</p>
</div>
);
}
}

export default Timer;

在这个示例中,MyComponent 组件每秒钟切换一次按钮的显示状态,getSnapshotBeforeUpdate 方法用于获取更新前的按钮可见状态,然后在 componentDidUpdate 方法中根据快照值判断按钮可见状态是否发生变化,并在控制台打印相应的信息。

函数组件模拟

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import React, { useState, useEffect } from 'react';

function Timer() {
const [seconds, setSeconds] = useState(0);

useEffect(() => {
const intervalId = setInterval(() => {
setSeconds(prevSeconds => prevSeconds + 1);
}, 1000);

// 返回一个清理函数,在组件即将卸载时执行
return () => {
clearInterval(intervalId);
};
}, []); // 仅在组件挂载时执行一次

return (
<div>
<p>Timer: {seconds} seconds</p>
</div>
);
}

export default Timer;

在这个示例中,我们使用 useEffect 钩子函数来模拟 componentWillUnmount 的功能。在 useEffect 的回调函数中,我们启动了一个定时器,并返回了一个清理函数,在组件即将卸载时清除定时器。这样可以确保在组件从 DOM 中移除之前清除所有的副作用,从而保持组件的健壮性和可预测性。


喜欢这篇文章?打赏一下支持一下作者吧!
【react】react 生命周期
https://www.cccccl.com/20211102/react/react 生命周期/
作者
Jeffrey
发布于
2021年11月2日
许可协议