Props-State

props

props 默认值

class Address extends Component {
  static defaultProps = {
    address: 'hangzhou',
  };

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

也可以使用 Address.defaultProps 的语法去设置默认值

使用 propTypes 进行类型检查

propsTypes 在使用时 需要引入 prop-types 库

注意 在 使用时 propTypes 要以小写开头

具体配置 官网已经写的很详细了 参考

import PropTypes from 'prop-types';
import React, { Component } from 'react';

class Address extends Component {
  static defaultProps = {
    address: 'hangzhou',
  };

  // 注意 这里的propTypes 是小驼峰
  static propTypes = {
    address: PropTypes.string.isRequired,
  };

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

export default class Example extends Component {
  render() {
    return (
      <div>
        <Address address={'123'} />
      </div>
    );
  }
}

上述验证 我们期望 address 传入一个字符串 但是父组件传入了一个数字

控制台 就会进行警告 但是它不是报错

state

和 props 不同的是 props 是外部数据来维护组件

而 state 是内部数据来维护组件

但是不管是 props 还是 state 都是不可变数据

即 我们不可以直接去修改原始数据的 props 和 state

必须 拷贝一份新的数据进行修改

setState

setState 继承自 Component 所以我们可以在组件中直接使用 setState 方法

我们来看一下以下代码片段

export default class Example extends Component {
  constructor(props) {
    super(props);

    this.state = {
      name: 'chou',
      age: 18,
    };
  }

  render() {
    return (
      <>
        <p>name : {this.state.name}</p>
        <p>age : {this.state.age}</p>
        <button onClick={() => this.handleNameChange()}>change name</button>
      </>
    );
  }

  handleNameChange() {
    this.setState({
      name: 'luckychou',
    });
  }
}

我们在 state 中保存了两个状态 name 和 age

但是 在点击按钮的时候 我们只修改了 name 这一个属性

所以 在这个操作的时候 age 属性 到底会有影响嘛

但其实 React 在 setState 这一个操作中 其实是合并了前后的 state

用到了 Object.assign({},oldState,newState)

异步 or 同步

我们修改一下刚刚的代码片段

在执行 setState 的前后 都打印一下 我们的 name 属性

  handleNameChange() {
    console.log(this.state.name)
    this.setState({
      name: 'luckychou',
    })
    console.log(this.state.name)
  }

我们可以惊奇的发现 两次的打印结果都是 chou 并未更新成 最新的数据

那如果我们需要拿到最新的 state 并基于最新的数据进行操作 该怎么办呢

这时 我们可以给 setState 传入第二个参数 这是一个回调函数

  handleNameChange() {
    console.log(this.state.name)
    this.setState(
      {
        name: 'luckychou',
      },
      () => {
        console.log('我是最新的数据哦,name : ', this.state.name)
      }
    )
    console.log(this.state.name)
  }

对比 三次打印结果 我们可以发现 使用这种方法 我们确实可以拿到最新的 state

我们继续修改我们的代码 添加 count 状态 和 button 按钮 并为其绑定事件

  handleCountAdd() {
    this.setState({
      count: this.state.count + 1,
    })
    this.setState({
      count: this.state.count + 1,
    })
    this.setState({
      count: this.state.count + 1,
    })
  }

那如果是这样呢

  handleCountAdd() {
    setTimeout(() => {
      this.setState({
        count: this.state.count + 1,
      })
    })
    setTimeout(() => {
      this.setState({
        count: this.state.count + 1,
      })
    })
    setTimeout(() => {
      this.setState({
        count: this.state.count + 1,
      })
    })
  }

未使用定时器的情况下 我们会得到超出预期的结果

虽然 事件内部执行了 三次 +1 的操作 但是点击按钮时 呈现的效果还是 只加了一次 1

而使用定时器则和我们的预期一致

OK 现在 我们来做一个总结

  • setState 在合成事件(onClick)和回调函数中是异步的

  • 在定时器和原生事件(通过 dom addEventListener)中是同步的

Last updated

Was this helpful?