前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >React--7: 组件的三大核心属性1:state

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

作者头像
用户4793865
发布2023-01-12 14:16:37
1.5K0
发布2023-01-12 14:16:37
举报
文章被收录于专栏:前端小菜鸡yym前端小菜鸡yym

这是我参与8月更文挑战的第14天,活动详情查看:8月更文挑战

1. 简单组件和复杂组件

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

那么什么是状态呢?

代码语言:javascript
复制
graph LR
A(人) --> B(状态) -->C(影响)-->D(行为)
代码语言:javascript
复制
graph LR
A(组件) --> B(状态) -->C(驱动)-->D(页面)

2. state

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

state 的使用 :我们做个例子点击改变天气 炎热还是凉爽

在这里插入图片描述
在这里插入图片描述

2.1 创建组件

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

代码语言:javascript
复制
// 1.创建类组件
class Weather extends React.Component{
    render(){
    console.log(this)

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

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

代码语言:javascript
复制
class Weather extends React.Component{
    constructor(???){
        
    }
    render(){
    console.log(this)

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

2.2 添加构造器

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

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

代码语言:javascript
复制
// 1.创建类组件
class Weather extends React.Component{
    constructor(props){
        super(props)
    }
    render(){
    console.log(this)

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

2.3 添加变量/属性

state 要写成对象

代码语言:javascript
复制
 constructor(props){
        super(props)
        this.state = {
            isHot:true
        }
    }

现在实例对象上的 state 中已经有我们的 isHot 了

在这里插入图片描述
在这里插入图片描述

下面我们只需要取出来这个值,并渲染出来

代码语言:javascript
复制
// 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

代码语言:javascript
复制
// 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方法。

代码语言:javascript
复制
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把原生的事件都变成了驼峰规则的。 所以我们要改成

代码语言:javascript
复制
 <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

代码语言:javascript
复制
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

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

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

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

在这里插入图片描述
在这里插入图片描述

2.4.6 setState

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

代码语言:javascript
复制
  demo(){
        const {isHot} = this.state
        this.state.isHot  = !isHot 
    }
}

怎么点击都没变化。那么们打印一下console.log(this.state.isHot) 发现值确实变化了

在这里插入图片描述
在这里插入图片描述

这个isHot值已经改变了,但是页面并不变化。我们看一下React开发者工具,无论我们怎么点击这个值都是不变的。React并不承认我们的操作。

在这里插入图片描述
在这里插入图片描述

⚠️ :状态不可以直接更改,需要API :setState this.state.isHot = !isHot 是 ❌ 的写法。下面的写法才是正确的。

代码语言:javascript
复制
 demo(){
        const {isHot} = this.state
        this.setState({isHot:!isHot})     
    }

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

代码语言:javascript
复制
  this.state = {
            isHot:true,
            wind:"风"
       }
       
     demo(){
        const {isHot} = this.state
        this.setState({isHot:!isHot}) 
        console.log(isHot)
       
    }
在这里插入图片描述
在这里插入图片描述

所以是一种合并。

3. 精简代码

3.1 去掉构造器

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

代码语言:javascript
复制
state = {
        isHot:true,
        wind:"风"
    }

可以 发现又 undefined 了。因为 demo 函数放在了Weather的原型对象上。

在这里插入图片描述
在这里插入图片描述

3.2 改造自定义函数

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

代码语言:javascript
复制
 demo = function(){
        const {isHot} = this.state
        this.setState({isHot:!isHot}) 
        console.log(isHot)
       
    }
在这里插入图片描述
在这里插入图片描述

我们再点击但是还是没有解决问题。 接下来,我们把函数换成箭头函数。发现好了。

代码语言:javascript
复制
demo=()=>{
        const {isHot} = this.state
        this.setState({isHot:!isHot}) 
        console.log(isHot)
       }

🤔 那么为什么那?

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

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

在这里插入图片描述
在这里插入图片描述

3.3 完整代码

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

代码语言:javascript
复制
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)
       
    }
}

4. 总结

4.1 理解

state是组件对象最重要的属性,值是对象(可以包含多个key value的组合)。

组件被称为“状态机”,通过更新组件的 state 来更新对应的页面显示(重新渲染组件)。

4.2 注意

组件中的render方法中的 this 为组件的实例对象

组件自定义方法中的 this 为 undefined,如何解决?

(1)强制绑定 this :通过函数对象的bind()

(2)箭头函数

状态数据,不能直接修改或更新,用 setState()

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-08-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 简单组件和复杂组件
  • 2. state
    • 2.1 创建组件
      • 2.2 添加构造器
        • 2.3 添加变量/属性
          • 2.4 改变state值 setState
            • 2.4.1 原生写法
            • 2.4.2 写在标签里
            • 2.4.3 函数是否需要小括号
            • 2.4.4 在demo函数中更改isHot的值
            • 2.4.5 自定义函数的this指向
            • 2.4.6 setState
        • 3. 精简代码
          • 3.1 去掉构造器
            • 3.2 改造自定义函数
              • 3.3 完整代码
              • 4. 总结
                • 4.1 理解
                  • 4.2 注意
                  相关产品与服务
                  云开发 CLI 工具
                  云开发 CLI 工具(Cloudbase CLI Devtools,CCLID)是云开发官方指定的 CLI 工具,可以帮助开发者快速构建 Serverless 应用。CLI 工具提供能力包括文件储存的管理、云函数的部署、模板项目的创建、HTTP Service、静态网站托管等,您可以专注于编码,无需在平台中切换各类配置。
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档