理解什么是 state ?
首先 我们用最通俗易懂的话来理解, 比如 每个人都有自己的状态 , 每个人的状态 都会影响 他的行为,
那么, 我们将这句话放到 react 中去理解,把人看作是 组件,组件也有自己的状态,组件的状态会影响
它的页面。
我们在游览各大网页时,会发现 网页上有一些数据,如个人信息 账号 以及一些新闻列表等等。 这些都
是数据, 我们将这些数据放在了页面上,那么是什么驱动着页面的改变呢? 是数据。 这时候我们只需要
将数据 放入状态 ( state ) 中 ,我们去更改状态 页面也会随之变化。
- 首先我们用脚手架创建一个 react 项目
- 启动 项目 进入 src / app.js 修改成如下文件
import React, { Component } from 'react'
export default class App extends Component {
render() {
console.log(this)
return (
<div>
app组件
</div>
)
}
}
- 打开 控制台可以看见 如下
- 我们在 render() 方法中 打印了 this 可以看见在这个组件的实例对象上面。已经有一个 state 了 ( 这就是react 给你准备好的状态 )
现在我们回到 第一个问题 理解什么是 state ?
1 . state 是组件对象最重要的属性 ,值是对象 ( 里面可以包含多个 key : value 的 组合 ) 虽然在初始化看到的是null , 在react之前的版本中 还是一个 { }
2 . 组件被称之为状态机 , 通过更新组件里的 state 来更新对应的页面显示 ( 重新渲染组件 )
需要注意的地方 : 因有函数时组件与类式组件 react 将状态放到了 实例对象里 函数时组件 连this都没有 哪儿来的 状态呢? 在考虑初学者未接触到 hooks
我们 先从 类 组件来说。
初始化 state
- 首先 我们新建一个组件 如下 :
import React, { Component } from 'react'
export default class App extends Component {
constructor(props) {
super(props)
// 初始化状态
this.state = {
isHot: true
}
}
render() {
console.log(this)
return (
<div>123</div>
)
}
}
我们在 类 中 放了一个 构造器 constructor , 调用了 super ( 传递的props 不在本章见做详细说明 我们先写上 )
- 在构造器里 我们改变了实例对象里面的 state 这时候 我们启动项目 打开控制台
可以看见 我们初始化好了 一个 状态 key : isHot value:true
- 读取状态 我们将 render 方法中的代码改为 如下:
render() {
console.log(this.state)
return (
<h2>今天天气很{this.state.isHot ? '炎热' : '寒冷'}</h2>
)
}
打开页面与控制台 我们查看一下
React 中的事件绑定
需要注意的是 原生js 中的 onclick , onblur … 等等 在 React 中 全部改为 onClick onBlur 这种小驼峰的写法
- 接下来 我们修改 代码如下
import React, { Component } from 'react'
export default class App extends Component {
constructor(props) {
super(props)
this.state = {
isHot: true
}
}
render() {
return (
<h2 onClick={ clickTitle() }>今天天气很{this.state.isHot ? '炎热' : '寒冷'}</h2>
)
}
}
function clickTitle() {
console.log('标题被点击了');
}
- 我们打开控制台可以看见 我们还没有点击 , 控制台就已经打印了 。
我们可以思考一下为什么 ?
onClick = { clickTitle() } 同等于 onClick = { 函数调用的返回值 }
我们将返回值 直接给到了 onClick 他就自动的去给你点了
我们将 onClick = { clickTitle() } 后面的调用给去掉 改为 onClick = { clickTitle }
重新回到页面 我们可以看到 已经可以进行正常的点击操作了
类方法中的 this
此处 我们接着上一个小节中的内容 继续 。
我需要 点击标题的时候 让炎热变成寒冷 这个时候怎么去处理? 我们需要将代码修改成 如下:
import React, { Component } from 'react'
export default class App extends Component {
constructor(props) {
super(props)
this.state = {
isHot: true
}
}
clickTitle() {
console.log('标题被点击了');
}
render() {
return (
<h2 onClick={ this.clickTitle }>今天天气很{this.state.isHot ? '炎热' : '寒冷'}</h2>
)
}
}
首先 我们只需要将 函数从实例的外面 放到实例的里面去
那么 clickTitle 这个方法放在哪儿了呢?
他放在了类的实例对象上,供实例使用
所以 我们需要在
<h2 onClick={ this.clickTitle }>今天天气很{this.state.isHot ? '炎热' : '寒冷'}</h2>
这句话中 改成 this.clickTitle
启动项目 发现 标题依然是可以被点击的
接下来 我们将函数内的代码改为
clickTitle() {
console.log(this.state.isHot);
}
这时 控制台就直接报错了
我们再去打印 this 时会发现 this 是 undefined
我们可以知道 constructor 和 render 中的 this 都是指组件的实例对象 ,那么自己定义的clickTitle 里的this为什么是undefined呢
首先我们要了解到 只有当 clickTitle 这个方法 是组件的实例对象去调用的时候 它里面的 this 才是clickTitle的实例对象
constructor 里的 this 一定是当前实例的 实例对象 是一个固定的东西
注意: 我们需要知道的是 clickTitle 在调用的时候 并不是App这个实例对象去调用他的
这时候 再思考一个问题 既然不是 这个实例去调用他的 那 this 为什么是 undefined 不是 window呢 ?
注意:在类中 所定义的方法 它会自动的去在你所定义的方法里面 开启严格模式 开启严格模式后 this 就是 undefined 是 类 自动帮你开启的
解决类中 this 的指向问题
在constructor 里 加一段代码 如下
constructor(props) {
super(props)
this.state = {
isHot: true
}
// 解决 this 的指向问题
this.clickTitle = this.clickTitle.bind(this)
}
这个时候 我们去控制台 点击标题 查看一下
this.clickTitle = this.clickTitle.bind(this) 这一段代码 本身是一个赋值语句 我们在实例对象本身加了一个方法 这个方法从那儿来的呢? 是从原型上来的
React 中 setState 的使用
此处 我们接着上一个小节中的内容 继续 。
我们将函数体的内容改为 如下 :
clickTitle() {
this.state.isHot = !this.state.isHot
}
运行项目后 发现 点击标题依然不能改变标题的内容
我们打印 函数里的 this.state.isHot
会发现 isHot的值确实在改变 但是为什么页面不更新呢
严重注意: state( 状态 ) 不可直接更改, this.state.isHot = !this.state.isHot 这一行是错误的写法
此处 我们需要借助 一个内置的 api 去更改state的值 setState() 。 我们在函数体内打印 this 可以找到
在函数体内修改如下代码 :
clickTitle() {
this.setState({ isHot: !this.state.isHot })
}
这时 我们点击 页面中的 标题 就可以进行切换了
注意: 修改state的值 必须使用 setState 来修改, 且 修改是一个合并的动作 并不是直接替换 setState调用几次 render 这个方法就会调用几次 可以自己打印试试
State 的简写方式
将代码改成 如下:
import React, { Component } from 'react'
export default class App extends Component {
// constructor(props) {
// super(props)
// this.state = {
// }
// this.clickTitle = this.clickTitle.bind(this)
// }
state = {
isHot: true
}
// clickTitle() {
// this.setState({ isHot: !this.state.isHot })
// }
clickTitle = () => {
this.setState({ isHot: !this.state.isHot })
}
render() {
return (
<h2 onClick={this.clickTitle}>今天天气很{this.state.isHot ? '炎热' : '寒冷'}</h2>
)
}
}
此处 我们将 state 从 constructor 直接拿出来
在类中 , 我们直接写一个赋值的语句 相当于 我们在 APP 这个实例对象上 新加了一个属性 属性的名字 是 state 它的值是 { isHot:true }
然后 在将 this.clickTitle = this.clickTitle.bind(this) 给注释掉
同样 我们在实例对象上 新增了一个方法 为 clickTitle 值 是一个 箭头 函数 这样就解决掉了 this 的指向问题 避免在 constructor 频繁的 使用bind 绑定this
将这两行 注释掉了以后 我们完全可以将 constructor 这个构造器 给注释掉, 因为我们没有在里面写任何的内容
以下为完整代码
import React, { Component } from 'react'
export default class App extends Component {
//初始化状态
state = {
isHot: true
}
//自定义方法 需要采用 赋值语句的形式 + 箭头函数
clickTitle = () => {
this.setState({ isHot: !this.state.isHot })
}
//渲染
render() {
return (
<h2 onClick={this.clickTitle}>今天天气很{this.state.isHot ? '炎热' : '寒冷'}</h2>
)
}
}