React 组件中 State 的定义、使用及正确更新方式
React 组件中 State 的定义、使用及正确更新方式
在 React 应用开发中,state
是组件内部用来存储和管理数据的关键概念。它允许组件根据不同的状态展示不同的 UI。本文将详细介绍state
的定义、使用方式以及如何正确地更新state
,帮助开发者更好地理解和运用这一核心特性。
1.1 state及其特点
State 与 props 类似,但是 state 是私有的,并且完全受控于当前组件。以下是一些重要的特点:
- 不要直接修改state:构造函数是唯一可以给
this.state
赋值的地方。 - state更新可能是异步的:出于性能考虑,React 可能会把多个
setState()
调用合并成一个调用。 - state更新会被合并:当你调用
setState()
的时候,React 会把你提供的对象合并到当前的 state。
1.2 state的定义和使用
目前React中的状态有两种使用方式:
1.2.1 ES6的类 - 构造函数
import React from 'react';
import ReactDOM from 'react-dom/client';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
date: new Date()
};
}
render() {
return (
<div>
现在的时间是:{this.state.date.toLocaleDateString()} {this.state.date.toLocaleTimeString()}
</div>
);
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
1.2.2 ES7的类 - 属性初始化器
import React from 'react';
import ReactDOM from 'react-dom/client';
class App extends React.Component {
state = {
date: new Date()
};
render() {
return (
<div>
现在的时间是:{this.state.date.toLocaleDateString()} {this.state.date.toLocaleTimeString()}!!!
</div>
);
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
1.3 如何正确的修改state
setState()
将对组件 state 的更改排入队列,并通知 React 需要使用更新后的 state 重新渲染此组件及其子组件。这是用于更新用户界面以响应事件处理器和处理服务器数据的主要方式。
将setState()
视为请求而不是立即更新组件的命令。为了更好的感知性能,React 会延迟调用它,然后通过一次传递更新多个组件。
setState()
并不总是立即更新组件。它会批量推迟更新。这使得在调用setState()
后立即读取this.state
成为了隐患。为了消除隐患,请使用componentDidUpdate
或者setState
的回调函数(setState(updater, callback)
),这两种方式都可以保证在应用更新后触发。
记住修改状态的三大原则:
- 不要直接修改 State
- state 的更新可能是异步的
- state 的更新会被合并
1.4 this.setState()方法及其特点
setState()
会对一个组件的state
对象安排一次更新。当 state 改变了,该组件就会重新渲染。setState()
可以添加两个参数,setState()
的第二个参数为可选的回调函数,它将在setState
完成合并并重新渲染组件后执行。
1.4.1 传递函数
参数一为带有形式参数的updater
函数:
this.setState((state, props) => stateChange[, callback]);
import React from 'react';
import ReactDOM from 'react-dom/client';
class App extends React.Component {
state = {
count: 100
};
render() {
return (
<div>
{this.state.count}
<button
onClick={() => {
this.setState((state, props) => {
console.log(state, props);
return {
count: state.count + 1
};
});
this.setState((state, props) => {
console.log(state, props);
return {
count: state.count + 1
};
});
this.setState((state, props) => {
console.log(state, props);
return {
count: state.count + 1
};
});
}}
>
加
</button>
</div>
);
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
updater
函数中接收的state
和props
都保证为最新。updater
的返回值会与state
进行浅合并。
1.4.2 传递对象
import React from 'react';
import ReactDOM from 'react-dom/client';
class App extends React.Component {
state = {
count: 10
};
render() {
return (
<div>
{this.state.count}
<button
onClick={() => {
this.setState({
count: this.state.count + 1
});
this.setState({
count: this.state.count + 1
});
this.setState({
count: this.state.count + 1
});
console.log(this.state.count);
}}
>
加
</button>
</div>
);
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
这种形式的setState()
是异步的,并且在同一周期内会对多个setState
进行批处理,相当于:
Object.assign(
prevState,
{count: this.state.count + 1},
{count: this.state.count + 1},
...
)
后调用的setState()
将覆盖同一周期内先调用setState
的值,因此商品数仅增加一次。如果后续状态取决于当前状态,建议使用 updater 函数的形式代替(前面案例已经实现)。或者在第二个参数中再继续操作。
import React from 'react';
import ReactDOM from 'react-dom/client';
class App extends React.Component {
state = {
count: 10
};
render() {
return (
<div>
{this.state.count}
<button
onClick={() => {
this.setState(
{
count: this.state.count + 1
},
() => {
this.setState(
{
count: this.state.count + 1
},
() => {
this.setState({
count: this.state.count + 1
});
}
);
}
);
console.log(this.state.count); // 10
}}
>
加
</button>
</div>
);
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
总结
通过本文的介绍,我们了解了state
在 React 组件中的重要性,以及如何在 ES6 和 ES7 类组件中定义和使用state
。同时,我们还探讨了正确更新state
的方法,包括使用setState()
方法时需要注意的事项。遵循这些最佳实践,可以帮助我们避免常见的陷阱,提高应用的性能和可靠性。