处理state
简单来说, State 用于修改组件的内部数据. 默认情况下只能在Class组件中使用state。得益于Hooks的出现,我们也可以在函数组件中使用state。
上一小结我们学习了属性props,可以在组件中读取和渲染属性。Props
Props不能修改
Props 的问题是它不能被修改.
我们一起来查看以下这段代码,看有什么问题:
import React from 'react';
export default class Element extends React.Component {
// THIS WON'T WORK
changeName() {
this.props.name = 'new name';
}
render() {
return (
<div>
<div>{this.props.name}</div>
<button onClick={() => this.changeName()} >change</button>
</div>
)
}
}
上例中尝试修改name 属性,修改失败!我们需要使用state来做这件事。
创建state
创建state有两种方式:
-
在构造函数中创建. 在构造函数内创建并初始化
state:constructor() { this.state = { cart: [], discounts: [] } } -
创建内联字段. 除了构造函数,也可以创建一个内联字段并初始化:
class Element extends React.Component { state = { field : 'some value' } }
注意,该语法需要babel 配置支持classProperties,参照 Props
访问state
使用 this.state 访问state,使用点操作符访问state属性:
this.state.nameOfYourProperty
解构(ES6的语法)
当有多个属性需要渲染的时候,我们可以使用 解构 语法 提取 多个属性。解构是ES6的语法糖,可以替代this.state.something来使用:
render() {
return (
<React.Fragment>
<div>{this.state.name}</div>
<div>{this.state.description}</div>
</React.Fragment>
)
}
使用 解构 语法,我们可以这样写:
render() {
const { name, description } = this.state
return (
<React.Fragment>
<div>{name}</div>
<div>{description}</div>
</React.Fragment>
)
}
注意下面一行 提取 了你需要用到的属性:
const { name, description } = this.state
将属性提取到对应的 name 和 description 变量后,就可以省略前面的 this.state 了。
注意: 解构语法蜜糖香不?同样的语法可也可以用在
this.props上.
修改 state
如何修改state? 不能像之前使用 this.props 一样操作 this.state。 直接赋值修改 this.state是错误的:
// wouldn't work
this.state.name = 'new value';
需要使用 setState() 方法来修改state。 setState() 很强大,它可以修改一个属性,也可以同时修改多个或所有属性。先初始化属性,包含 name 和 description:
this.state = {
name: 'initial name',
description: 'initial description'
}
使用 setState() 修改部分属性:
this.setState({
name: 'new name'
})
这条指令只修改了 name 属性, description 属性保持不变。
注意该操作是异步的,如果你想查看setState() 什么时候完成 ,可以在第二个参数使用回调函数:
this.setState({
name: 'new value'
}, function() {
// change has happened here
})
案例 - 使用 state
该项目将创建一个可以修改 state 的组件。 在React中,组件分为有状态组件和无状态组件,前者可以修改 state ,后者只渲染数据。
-
运行
git clone克隆开始项目:git clone https://github.com/softchris/react-starter-project my-component-app cd my-component-app该开始项目基于教程使用webpack配置react项目
-
运行
npm install命令安装依赖包:npm install -
在 src 目录添加
Person.js文件,并添加以下内容:import React from 'react'; export default class Person extends React.Component { constructor(props) { super(props); // this call is needed to turn it into a React component this.state = { name : this.props.name } } changeName(evt) { // implement console.log(evt); } render() { return ( <div> <div>{this.props.name}</div> <div><input type="text" onChange={(evt) => this.changeName(evt)} value={this.state.name} /></div> </div> ) } } 我们将做一个包含输入框的组件,当键入输入框的时候,输入框内容会同步修改。
-
在 index.js 文件中找到下面这段代码:
ReactDOM.render(
<div>{title}</div>,
document.getElementById('app')
);
修改成为:
ReactDOM.render(
<Person name={name} />,
document.getElementById('app')
);
在文件的顶部引入Person:
import Person from './Person';
以上代码确保 Person 组件的内容可以成功渲染。
-
在终端运行项目 npm start:
npm start -
打开浏览器访问 http://localhost:8080. 查看结果:
现在试试修改输入框,输入框内容没有发生任何改变。
我们想要在键入输入框的同时,修改输入框的内容。现在输入框的内容设置为 this.state.name :
<input onChange={(evt) => this.changeName(evt)} value={this.state.name}>
changeName() 方法将在每次键入的时候调用,但是我们还没有在 changeName() 里添加内容,下一步完成它。
-
打开 Person.js 修改
changeName()方法,在其中设置state:changeName(evt) { this.setState({ name: evt.target.value }) }保存,查看浏览器.
-
再次修改输入框内容,成功。
-
通过交互组件更新state,确保每次用户输入的时候都更新状态,使用户输入与组件状态保持同步
代码参考
👉 查看示例
小结
学会了如何使用构造函数初始化state,学会了使用setState()修改state属性。