React--7: 组件的三大核心属性1:state

1. 简单组件和复杂组件

简单组件:无 state
复杂组件:状态 state

那么什么是状态呢?

状态
影响
行为
组件
状态
驱动
页面

2. state

标题深究其实是:组件(实例)的三大核心属性。
而 只有类组件才有实例,函数式组件根本没资格。为了解决函数式组件的这个问题 react 又推出了 hooks。

state 的使用 :我们做个例子点击改变天气 炎热还是凉爽
在这里插入图片描述

2.1 创建组件

我们要创建类组件 还是 函数式 组件?
当然是 类组件。

// 1.创建类组件
class Weather extends React.Component{
    render(){
    console.log(this)

        return <h2>今天天气很炎热</h2>
    }
}
// 2. 渲染
ReactDOM.render(<Weather/>, document.getElementById('root'))

然后我们需要 定义一个变量 isHot 来 改变炎热还是凉爽。state 在类的实例上。 那我们想要往 state 中添加变量,我们要对类的实例进行初始化操作,那就需要我们写构造方法。

class Weather extends React.Component{
    constructor(???){
        
    }
    render(){
    console.log(this)

        return <h2>今天天气很炎热</h2>
    }
}

2.2 添加构造器

那么 构造器中需要传什么参数?这要取决于 实例对象传递的参数,然而,这是React创建的 ,我们并看不到。

我们去官网看,它传了props。那需要写super吗?需要,这是类规定的。

// 1.创建类组件
class Weather extends React.Component{
    constructor(props){
        super(props)
    }
    render(){
    console.log(this)

        return <h2>今天天气很炎热</h2>
    }
}

2.3 添加变量/属性

state 要写成对象

 constructor(props){
        super(props)
        this.state = {
            isHot:true
        }
    }

现在实例对象上的 state 中已经有我们的 isHot 了
在这里插入图片描述
下面我们只需要取出来这个值,并渲染出来

// 1.创建类组件
class Weather extends React.Component{
    constructor(props){
        super(props)
        this.state = {
            isHot:true
        }
    }
    render(){
    console.log(this)

        return <div>

            <h2>今天天气很
            {
                this.state.isHot ? '炎热':'凉爽'
            }
            </h2>
        </div>     
    }
}

2.4 改变state值 setState

按钮点击改变值

2.4.1 原生写法

给 h2 标签添加 id 属性 使用方法:addEventListener 或 onClick

// ES6 中模块化语法
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';

// 1.创建类组件
class Weather extends React.Component{
    constructor(props){
        super(props)
        this.state = {
            isHot:true
        }
    }
    render(){
    console.log(this)

        return <div>

            <h2 id="title">今天天气很
            {
                this.state.isHot ? '炎热':'凉爽'
            }
            </h2>
        </div>
        
            
    }
}
// 2. 渲染
ReactDOM.render(<Weather/>, document.getElementById('root'))
// 原生方法 1
const title = document.getElementById("title")
title.addEventListener('click',()=>{
	console.log("标题被点击了")
}
// 原生方法 2
title.onClick=()=>{
	console.log("标题被点击了")
}

虽然两种方式可以实现点击事件,但是都用React了,尽量少写原生的js方法。

2.4.2 写在标签里

这种当然也是原生的方法。我们新写一个button标签在内部加入onclick。然后再写一个demo方法。

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';

// 1.创建类组件
class Weather extends React.Component{
    constructor(props){
        super(props)
        this.state = {
            isHot:true
        }
    }
    render(){
    console.log(this)

        return <div>

            <h2 id="title">今天天气很
            {
                this.state.isHot ? '炎热':'凉爽'
            }
            </h2>
             <button onclick="demo()">change weather</button>
        </div>
        
            
    }
}
// 2. 渲染
ReactDOM.render(<Weather/>, document.getElementById('root'))

function demo(){
	console.log("按钮被点击了")
}

我们会发现它报错了,因为不能使用onclick。那么我们用什么?用onClick,React把原生的事件都变成了驼峰规则的。
所以我们要改成

 <button onClick="demo()">change weather</button>

2.4.3 函数是否需要小括号

我们发现还没有点击,就已经打印了 “按钮被点击了”
在这里插入图片描述
那么这是为什么呢?React帮我们创建了一个Weather实例,通过实例调用了 render。就执行了<button onClick="demo()">change weather</button> 代码。要把函数的返回值赋过来,onClick="demo()" 是一个赋值语句,把右边的返回值赋值给onClick作为回调。demo函数的返回值是什么?是undefined。现在点击是没有效果的。

所以需要删掉小括号onClick="demo" ,这个含义是把右边的函数作为回调交给onClick事件,点击的时候才会调用函数
在这里插入图片描述
现在再点击按钮 达到了我们想要的效果。

2.4.4 在demo函数中更改isHot的值

我们解构赋值,拿到isHot

function demo(){
 const {isHot} = this.state
 console.log(isHot)
}

发现报错了。state没有被定义,那么究其根源是什么没有呢?是this。
在这里插入图片描述
为什么会没有this呢?
首先这个函数是我们自定义的函数,而Babel在将我们的jsx转为js的时候是严格模式。它不允许自定义的函数的this指向window。

🤔 在我们自定义的demo函数中根本拿不到组件的实例对象,怎么办?
我们在最外部定义一个that变量,然后在构造器中将this也就是实例对象赋值给that。最后,在函数中打印that
在这里插入图片描述
虽然这样是实现了,但是不是很完美。
我们把demo方法放入类中,发现function报错了,因为类里面不可以这么写。
在这里插入图片描述
去掉function就好了
在这里插入图片描述
现在的demo放在类的原型对象上了,供实例对象使用。
通过Weather实例调用demo时,demo中的this就是Weather实例。

此时就不需要that了。现在会报错demo函数undefined。因为demo是实例对象下的,所以需要this.demo
在这里插入图片描述
点击后还是会报错,因为此时的this是undefined

2.4.5 自定义函数的this指向

此时onClick={this.demo} 根本没有调用demo方法,只是通过类的实例对象沿着原型链找到了demo,然后把这个函数交给onClick作为回调了。直接从堆中将函数调用,根本不是从实例对象中调用。类中的方法默认开启了局部的严格模式。因此,此时的this是undefined。

使用bind

 this.demo = this.demo.bind(this)
  • 本质上来说是一个赋值语句,先看右边,实例上其实是没有demo的,那么为什么不会报错呢?它会按着原型链找到原型上的,也就找到了我们定义的函数。
  • 右边的代码一旦运行完,就会有了一个函数,而且这个函数的this成功的变成了Weather的实例对象。
  • 再看左边,将这个函数放到了实例自身,还给这个函数起了个名字,this.demo。

此时我们在函数中打印 this ,会发现自身也有demo方法了。那么每次点击调用执行的是自身的,还是原型上的呢🤔 ?按着原型链去找在自身上就已经找到了,就不会再去原型上去找了。

那原型上的demo方法可以删掉吗🤔 ?当然不可以,是因为原型上有demo方法,我们才可以生成一个新的挂在实例自身。
在这里插入图片描述

2.4.6 setState⁄

在demo函数中获取原来isHot的值。并将它取反再赋回去。

  demo(){
        const {isHot} = this.state
        this.state.isHot  = !isHot 
    }
}

怎么点击都没变化。那么们打印一下console.log(this.state.isHot) 发现值确实变化了
在这里插入图片描述
这个isHot值已经改变了,但是页面并不变化。我们看一下React开发者工具,无论我们怎么点击这个值都是不变的。React并不承认我们的操作。
在这里插入图片描述
⚠️ :状态不可以直接更改,需要API :setState
this.state.isHot = !isHot 是 ❌ 的写法。下面的写法才是正确的。

 demo(){
        const {isHot} = this.state
        this.setState({isHot:!isHot})     
    }

那么思考一下 🤔
这个setState是合并还是覆盖?
我们再在state中加一个 wind 变量 ,在改变 isHot时,wind这个值丢不丢,不丢,就是合并,否则是覆盖。

  this.state = {
            isHot:true,
            wind:"风"
       }
       
 	demo(){
        const {isHot} = this.state
        this.setState({isHot:!isHot}) 
        console.log(isHot)
       
    }

在这里插入图片描述
所以是一种合并。

3. 精简代码

3.1 去掉构造器

为什么写构造器?
因为要做一些初始化的操作。感不感觉是没地方写了才写到构造器里的。
类中是可以直接写赋值语句的 。所以给state赋值,不需要非得写在构造器中。

state = {
        isHot:true,
        wind:"风"
    }

可以 发现又 undefined 了。因为 demo 函数放在了Weather的原型对象上。
在这里插入图片描述

3.2 改造自定义函数

首先,我们自定义的方法大部分都是作为事件回调的。
那我们把这个函数改一下:现在是一个赋值语句。现在这个demo就放在Weather实例自身了,就不在原型上了。

 demo = function(){
        const {isHot} = this.state
        this.setState({isHot:!isHot}) 
        console.log(isHot)
       
    }

在这里插入图片描述
我们再点击但是还是没有解决问题。
接下来,我们把函数换成箭头函数。发现好了。

demo=()=>{
        const {isHot} = this.state
        this.setState({isHot:!isHot}) 
        console.log(isHot)
       }

🤔 那么为什么那?

  • 箭头函数是没有this的,那在箭头函数里使用 this 会报错吗?不会,他会去找其外层函数的 this
    去使用。找外侧,就找到了类里面的区域。
  • 我们打印一下 空白区域的 this ,可以吗?可以看到已经报错了。因为这是类中,不能随便写代码。

在这里插入图片描述
那么我们怎么看空白区域的 this ? 看不了了?我们刚才说过箭头函数中的 this 就是它外层的 this指向。所以我们在 箭头函数中 打印的 this 就是空白区域的 this。可以发现是组件的实例对象。
在这里插入图片描述

3.3 完整代码

简化后 ,可以不需要写构造器了,自定义方法要用赋值语句的形式+箭头函数

class Weather extends React.Component{
    state = {
        isHot:true,
        wind:"风"
    }
    render(){
    console.log(this)

        return <div>

            <h2>今天天气很
            {
                this.state.isHot ? '炎热':'凉爽'
            }
            </h2>
            <button onClick={this.demo}>change weather</button>
        </div>
    }

    demo=()=>{
        const {isHot} = this.state
        console.log(this,"this")
        this.setState({isHot:!isHot}) 
        console.log(isHot)
       
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值