0202state详解-组件-React

1 state简介

React中没有state(状态)的组件称为简单组件;有state称为复杂组件。

  • 理解
    • state是组件对象最重要的属性之一,值是对象(1个或者多个key-value组合)
    • 组件被称为状态机,通过更新组件的state来更新对应页面显示(重新渲染组件)

下面我们来一步一步认识state,并最后给出日常开发中使用state的形式。

2 初始化state

下面展示一个小案例,通过点击文本,来切换今天的天气,如下图2-1所示:

在这里插入图片描述

第一步先把文本通过React组件显示在页面上,代码2-1如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>组件对象三大属性之一state</title>
</head>
<body>
  <div id="test"></div>
  <script type="text/javascript" src="../js/react.development.js"></script>
  <script type="text/javascript" src="../js/react-dom.development.js"></script>
  <script type="text/javascript" src="../js/babel.min.js"></script>

  <script type="text/babel">

    // 1.类式组件
  class Weather extends React.Component {
    constructor(props) {
      super(props)
      // 初始化状态
      this.state = {isHot: false}
    }
    render() {
     // 读取状态
      console.log(this);
      return <h2>今天天气很{this.state.isHot? '炎热': '凉爽'}</h2>
    }
   }
    // 2.渲染虚拟DOM到页面
    ReactDOM.render(<Weather/>, document.getElementById('test'))
  </script>
</body>
</html>

state初始化及访问步骤:

  1. 在构造函数中this.state=值(对象)
  2. 在render方法中{}内this.state.key访问key对应的值

注:

  1. state是Weather实例中的属性,要想初始化需要借助构造器。
  2. render中的this就是当前组件的实例对象

问题:

  1. Weather实例不是由我们new,而是React创建的,React在创建时,构造函数传递了那些参数呢?
  2. 构造器中的super能不能省略呢?

借助开发者工具查看下组件实例,如下图2-1所示:

在这里插入图片描述

3 React中事件绑定

在上面呢,我们完成了state的初始化和读取,实现了文本的展示,那么如果通过鼠标点击来完成切换呢?

参考js很容易想到,要通过绑定鼠标点击事件来完成。那么在Reac中如何绑定事件呢?

第一步在类中定义鼠标点击处理函数:

    changeWeather() {
      console.log(this);
      this.state.isHot = !this.state.isHot
    }

第二步在render函数返回标签上绑定点击事件:

    render() {
      // 读取状态
      console.log(this);
      return <h2 onClick={this.changeWeather}>今天天气很{this.state.isHot ? '炎热' : '凉爽'}</h2>
    }

注:

  1. onClick遵循小驼峰命名规则
  2. this.changeWeather后不加()

鼠标点击查看console输出:

undefined
Inline Babel script:25 Uncaught TypeError: Cannot read properties of undefined (reading 'state')

为啥呢?下面讲解

4 类方法中this指向问题

示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>3_类方法中this的指向</title>
</head>
<body>
  <script type="text/javascript">
    class Person {
      constructor(name, age) {
        this.name = name
        this.age = age
      }
      
      speak() {
        // speak方法放在Person类原型对象上,供实例使用
        // 通过Person实例调用本方法,方法中的this指向Person实例
        // 类中普通方法默认开启严格模式
        console.log(this);
      }
    }

    const p1 = new Person('zhangsan', 25)
    // 通过实例调用类方法
    p1.speak()
    // 直接调用方法,因为默认开启了严格模式,this为undefied
    const f1 = p1.speak
    f1()

    function demo1() {
      console.log(this);
    }

    function demo2() {
      'use strict'
      console.log(this);
    }

    demo1()
    demo2()
  </script>
</body>
</html>

输出:

Person
undefined
Window
undefined

5 解决React类组件方法this指向

解答下上面为什么点击,调用changeWeather(),输出是undefied问题?

onClick={this.changeWeather},这里为鼠标点击之前,通过this实例原型链找到changeWeather方法,交给onClick用于回调。当点击的时候属于直接调用changeWeather()方法,而不是通过Weather的实例对象。

又因为类中普通方法默认开启严格模式,且经过babel翻译,所以是undefined不是windows也不是Weather实例

解决方案一:既然此处是非实例调用,导致this执行改变,那么我们通过bind方法改变this指向为Weather实例并重新放置在Weather实例上。

代码调整如下:

  <script type="text/babel">

    // 1.类式组件
  class Weather extends React.Component {
    constructor(props) {
      super(props)
      // 初始化状态
      this.state = {isHot: false}
      this.changeWeather = this.changeWeather.bind(this)
    }
    render() {
      // 读取状态
      console.log(this);
      return <h2 onClick={this.changeWeather}>今天天气很{this.state.isHot ? '炎热' : '凉爽'}</h2>
    }
    changeWeather() {
      // changeWeather放在了哪里?Weather的原型对象上,供实例使用
      // 由于changeWeather上作为onClick的回调,所以不是通过实例调用的,上直接调用
      // 类中的方法默认开启了严格模式,所以changeWeather中的this为underfided
      // console.log(this);
      let isHot = this.state.isHot
      this.state.isHot = !isHot
      console.log(this.state.isHot);
    }
   }
    // 2.渲染虚拟DOM到页面
    ReactDOM.render(<Weather/>, document.getElementById('test'))

解决方案二:我们把一个匿名函数交给onClick回调,匿名函数内部执行this.changeWeather()方法,此时this就是Weather实例。

调整代码如下:

  class Weather extends React.Component {
    constructor(props) {
      super(props)
      // 初始化状态
      this.state = {isHot: false}
    }
    render() {
      // 读取状态
      console.log(this);
      // 匿名函数
      return <h2 onClick={() => this.changeWeather()}>今天天气很{this.state.isHot ? '炎热' : '凉爽'}</h2>
    }
    changeWeather() {
      // changeWeather放在了哪里?Weather的原型对象上,供实例使用
      // 由于changeWeather上作为onClick的回调,所以不是通过实例调用的,上直接调用
      // 类中的方法默认开启了严格模式,所以changeWeather中的this为underfided
      // console.log(this);
      let isHot = this.state.isHot
      this.state.isHot = !isHot
      console.log(this.state.isHot);
    }
   }

其他代码同上

不管是第一种bind改变this执行,还是事件监听回调绑定匿名函数都可以把上面的问题解决,但是鼠标点击,页面并没有和预想的一种,点击切换天气,这又是啥问题呢?明明this.state.isHot的值在控制台打印是改变了的。下面5setState部分给出解答。

5 setState

5.1 更新state状态数据方式

react中state中状态数据,不可直接更改,需要借助内置的API(setState)更改。

继续调整changeWeather()方法中更改数据的方式,如下:

    changeWeather() {
      // 状态需要通过setState修改, 且更新是一种合并,不是替换
      this.setState({isHot: !this.state.isHot})
    }

该setSate()放置在React.Component原型对象上,可以直接通过this调用。

5.2 更新state整体替换还是合并相同项?

那么this.state的值是一个对象,我们单独更新其中一个key-value,结果是整体替换还是合并原有的this.state值呢?

测试,在this.state初始化中在加一个key-value,如下

    constructor(props) {
      super(props)
      // 初始化状态
      this.state = {isHot: false, wind: '微风'}
    }

如下图所示:在这里插入图片描述

React的state中的状态数据更新是合并更新,相同key替换对应的值,不同保持原样。

现象:

  • 开发者工具中value值更新并不实时,有一定延迟,不知道啥原因。

5.3 关于构造器、render方法调用次数

  • 构造器:组件实例化时才执行,即页面有几个该类型组件实例,调用几次
  • render方法:1+n次,1是初始化时调用,n为状态更新次数

6 state简写

在日常开发中,我们怎么使用state呢?

需求说明:

  1. 我们只是想初始化转态
  2. 确保自定义方法中this指向组件实例

解决:

  1. 把state在类中方法外初始化
  2. 使用箭头函数

知识点:

  • 实例变量

    • 定义:实例变量是类中方法外的变量,不过没有static修饰,也叫对象变量(new出来的);或者构造方法this.XXX

    • 作用有效范围:实例变量在对象创建的时候创建,在对象被销毁的时候销毁;

    • 默认值:实例变量具有默认值。数值型变量的默认值是0,布尔型变量的默认值是false,引用类型变量的默认值是null。变量的值可以在声明时指定,也可以在构造方法中指定;

  • 箭头函数:箭头函数内部this为其外层所在区域的this。如果在类中为类的实例对象;否则为全局对象window。

简化代码如下,其他同上:

    // 1.类式组件
  class Weather extends React.Component {
    // 初始化state
    state = {isHot: false, wind: '微风'}

    render() {
      return <h2 onClick={this.changeWeather}>今天天气很{this.state.isHot ? '炎热' : '凉爽'},{this.state.wind}</h2>
    }
    // =赋值表示changeWeather是实例方法
    changeWeather = () => {
      this.setState({isHot: !this.state.isHot})
    }
   }

7 问题解答

  • 2.1-暂时给出官网参考,参考官网首页,如下图7-1所示:

    在这里插入图片描述

    • props是什么?下个篇章讲解props
  • 2.2 类的语法规定:如果B类继承A类,而A类中写了构造器,那么B类构造器中super必须要调用。

后记

❓QQ:806797785

⭐️源代码仓库地址:https://gitee.com/gaogzhen/react-study

参考:

[1]尚硅谷React教程(2022加更,B站超火react教程)[CP/OL].2020-12-15.p7-p19.

[2]JS中Class类的静态属性和静态方法[CP/OL].

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gaog2zh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值