[React 2021新书]105、处理状态

303 阅读4分钟

React新手村

处理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

将属性提取到对应的 namedescription 变量后,就可以省略前面的 this.state 了。

注意: 解构语法蜜糖香不?同样的语法可也可以用在 this.props 上.

修改 state

如何修改state? 不能像之前使用 this.props 一样操作 this.state。 直接赋值修改 this.state是错误的:

// wouldn't work
this.state.name = 'new value';

需要使用 setState() 方法来修改state。 setState() 很强大,它可以修改一个属性,也可以同时修改多个或所有属性。先初始化属性,包含 namedescription:

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 ,后者只渲染数据。

  1. 运行 git clone 克隆开始项目:

    git clone https://github.com/softchris/react-starter-project my-component-app
    cd my-component-app
    

    该开始项目基于教程使用webpack配置react项目

  2. 运行 npm install 命令安装依赖包:

    npm install
    
  3. 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>
        )
      }
    }
    

    ​ 我们将做一个包含输入框的组件,当键入输入框的时候,输入框内容会同步修改。

  4. index.js 文件中找到下面这段代码:

ReactDOM.render(
  <div>{title}</div>,
  document.getElementById('app')
);

修改成为:

ReactDOM.render(
  <Person name={name} />,
  document.getElementById('app')
);

在文件的顶部引入Person:

import Person from './Person';

以上代码确保 Person 组件的内容可以成功渲染。

  1. 在终端运行项目 npm start:

    npm start
    
  2. 打开浏览器访问 http://localhost:8080. 查看结果:

image-20210815212117281的副本.png

现在试试修改输入框,输入框内容没有发生任何改变。

我们想要在键入输入框的同时,修改输入框的内容。现在输入框的内容设置为 this.state.name

<input onChange={(evt) => this.changeName(evt)} value={this.state.name}>

changeName() 方法将在每次键入的时候调用,但是我们还没有在 changeName() 里添加内容,下一步完成它。

  1. 打开 Person.js 修改 changeName() 方法,在其中设置state:

      changeName(evt) {
        this.setState({
          name: evt.target.value
        })
      }
    

    保存,查看浏览器.

  2. 再次修改输入框内容,成功。

  3. 通过交互组件更新state,确保每次用户输入的时候都更新状态,使用户输入与组件状态保持同步

代码参考

👉 查看示例

小结

学会了如何使用构造函数初始化state,学会了使用setState()修改state属性。