react技术全家桶(10)对state的理解

函数式组件用于简单组件 无状态的state 就是简单组件
类式组件用于复杂组件 有状态的 state 就是复杂组件

在这里插入图片描述
state就是在组件实例的身上。MyComponent类本身没有 实例才有。

实现一个功能 今天天气很凉爽 点击一下 变为今天天气很炎热。
搭好架子:
//创建类式组件
class Weather extends React.Component{

      render(){
          return <h1>今天天气很炎热</h1>
      }
  }
  //渲染
  ReactDOM.render(<Weather/>,document.getElementById('test'));

要做到变化,如何做,定义一个表示来区分凉爽和炎热。
打算给组建实例化的state字段赋值true或者false 来决定展示凉爽和炎热
但是呢?如果给组件实例化,因为new MyComponent是React帮我们做的,我们只能使用构造器了,因为state是继承React.Component带来的,所以在构造器中使用super方法,就会有state属性了,但是构造器传啥,我们先看官方的例子 先使用,之后讲解。
constructor(props){
super(props)
this.state={isHot:true}
}
在这里插入图片描述
如图能看到这个state:{isHot:true}是因为打日志了:
class Weather extends React.Component{
constructor(props){
super(props)
this.state={isHot:true}
}
render(){
console.log(this)
return

今天天气很炎热


}
}
接下来就是从state中读取数据了:
render(){
console.log(this)//这里的this就是Weather的实例,所以可以获取到state
return

今天天气很{this.state.isHot?‘炎热’:‘凉爽’}


}
接下来就是动态变化state了。
原生三种方式点击事件绑定:
class Weather extends React.Component{
constructor(props){
super(props)
this.state={isHot:true}
}
render(){
console.log(this)

          return <h1 id="title">今天天气很{this.state.isHot?'炎热':'凉爽'}</h1>
      }
  }
  //渲染
  ReactDOM.render(<Weather/>,document.getElementById('test'));

//方式一:
const title=document.getElementById(“title”);
title.addEventListener(‘click’,()=>{
console.log(‘标题被点击了’)
})
//方式二:
const title = document.getElementById(“test”);
title.οnclick=()=>{
console.log(“标题又被点击了”)
}
方式三:
class Weather extends React.Component{
constructor(props){
super(props)
this.state={isHot:true}
}
render(){
console.log(this)

          return <h1 onclick="demo">今天天气很{this.state.isHot?'炎热':'凉爽'}</h1>
      }
  }
  //渲染
  ReactDOM.render(<Weather/>,document.getElementById('test'));

function demo(){
    alert("标题被点击了啦")
}
bingo 报错了:

在这里插入图片描述
没有onclick属性 是不是用onClick C大写;
return

今天天气很{this.state.isHot?‘炎热’:‘凉爽’}


改为大写后: 特么 还报错:
在这里插入图片描述
onClick应该被一个函数监听,但是拿到了一个字符串,意思是不能是"demo()"写法。 原生这么写可以 在React不行。
把双引号去掉:
return

今天天气很{this.state.isHot?‘炎热’:‘凉爽’}

在这里插入图片描述

骂了个巴子 又出问题了,没报错 但是一打开就调用demo方法 还没点击呢。

这是因为React拿到Weather实例后执行render方法,就会执行到onClick={demo()} 这是一个赋值语句,等号右边会执行的 意思是吧demo()的结果赋值给onClick,所以点击事件不生效的。
所以呀要把括号删除,意思是把demo这个函数赋值给onClick 让onClick回调。
return

今天天气很{this.state.isHot?‘炎热’:‘凉爽’}


这下点击事件就解决了,接下来看如何根据state来动态改变true和false

重点来了:
想要在点击事件中获取state,比如:
function demo() {
console.log( this.state.isHot);
}
结果:
在这里插入图片描述

在这里插入图片描述
demo是在script标签中,又被babel解释,babel开启严格模式 所以this就是未定义 如果babel不开启严格模式 this表示的是window

所以在组件React创建Weather的实例对象的时候,demo方法拿不到该组件的实例对象,固然就拿不到state,这可如何是好?
可以定义全局 将this交出去。

let that;
在构造函数中传值;
constructor(props) {
super(props)
this.state = { isHot: true }
that=this;
}
然后在demo中使用:
function demo() {
that.state.isHot
}
}
问题解决。如果所示:
在这里插入图片描述
如果使用that 这种写法 就不标准了。有点繁琐 意思是不要把this交出去,然后再使用。
所以将dmeo移动到类组件中。
代码如下:
//创建类式组件
class Weather extends React.Component {
constructor(props) {
super(props)
this.state = { isHot: true }
}
render() {
console.log(this)

            return <h1 onClick={demo}>今天天气很{this.state.isHot ? '炎热' : '凉爽'}</h1>
        }
    function   demo() {
            this.state.isHot
        }
    }

不好意思 方法移动到weather组件中报错了,坑的就是你。
在组件中定义方法不需要function关键字,同时该方法给this使用的,所以使用{this.demo}如下:
class Weather extends React.Component {
constructor(props) {
super(props)
this.state = { isHot: true }
}
render() {
console.log(this)

            return <h1 onClick={this.demo}>今天天气很{this.state.isHot ? '炎热' : '凉爽'}</h1>
        }
        demo() {
            this.state.isHot //这么使用有问题  下面解释
        }
    } 
   又报错了 漂亮:

在这里插入图片描述
state没定义 什么鬼。demo不是通过weather对象调用的,所以 this不是weather的实例对象。那demo是谁调用的。
且听下面分析:
举个例子:
class Person{
study(){
console.log(this);
}
}

const p1 = new Person(‘tom’,18);
p1.study(); //person的实例再调用
const x = p1.study; //将study函数赋值给x
x();//这个时候this丢失 了 为underfind 此处调用还是执行study函数 但是此时是window在调用不是person的实例再调用。 类中的方法默认开起来局部的严格模式所以就是underfind

再看react中的原因,onClick={this.demo} 当执行到这里是因为将weather的demo方法赋值到了onClick上,然后当用户点击的时候有window执行onClick(),demo方法是类中的方法 默认开起严格模式 所以是uniderfind。

解决方案:
在构造器中加入:
this.demo = this.demo.bind(this);
完整代码:
constructor(props) {
super(props)
this.state = { isHot: true }
this.demo = this.demo.bind(this);
}
demo() {
// this.state.isHot
console.log(this)
}
原理:this.demo找到原型上的demo方法然后通过bind方法改变this 该成啥 就看传的什么参数 传递的是React创建的那个实例。
所以demo方法中使用this 就是React创建的weather组件的实例。然后将这个新的方法赋值给了实例对象的demo方法。注意这个时候的demo方法是实例对象的 不是原型对象的

99八十一难拿到了实例对象并且获取到了state,现在就是点击改变state了。
demo() {
const isHot = this.state.isHot;
this.state.isHot = !isHot
}
我你大妈 没有效果呀。
打印出this.state.isHot
console.log(this.state.isHot)
在这里插入图片描述

已经改了这个值了 。为啥没效果呢
对于这种直接修改的( this.state.isHot = !isHot),React不认为修改了 所以没有刷新组件。
通过工具看,点击1万次,isHot永远是false.
在这里插入图片描述
解决方案:要用React的API修改state
demo() {
const isHot = this.state.isHot;
// this.state.isHot = !isHot 直接修改 React不认 要用React的API修改
this.setState({isHot:!isHot});//state是个对象所以不能直接给true或者false
console.log(this.state.isHot)
}
终于圆满结束了。

细节:
1.this.setState({isHot:!isHot}) 这个动作是合并不是替换 比如之前state对象有两个keyvalue 这次只给了一个keyvlaue 那么会替换原来有的keyvalue 不会动其他的keyvalue

2.点击的时候凉爽和炎热交替,这个过程构造器调用了几次 调用了一次。
render调用了几次 1+n次。 1是初始化的那次 n是每次修改的时候就要刷新。
demo调用了几次 点击几次 调用几次

源码:

11.状态
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值