state
理解
- state是组件对象最重要的属性, 值是对象(可以包含多个key-value的组合)
组件被称为”状态机”, 通过更新组件的state来更新对应的页面显示(重新渲染组件)
注意事项
组件中render方法中的this为组件实例对象
- 组件自定义的方法中this为undefined,如何解决?
a) 强制绑定this: 通过函数对象的bind()
b) 箭头函数 - 状态数据,不能直接修改或更新
this.state是纯js对象,在vue中,data属性是利用Object.defineProperty处理过的,更改data的 数据的时候会触发数据的 getter 和 setter ,但是React中没有做这样的处理,如果直接更改的话, react是无法得知的,所以,需要使用特殊的更改状态的方法 setState 。复杂形式代码
class Weather extends React.Component{//构造器调用几次? ———— 1次constructor(props){console.log('constructor');super(props)//初始化状态this.state = {isHot:false,wind:'微风'}}//render调用几次? ———— 1+n次 1是初始化的那次 n是状态更新的次数,但是一次性调用多次setData,render只更新一次render(){console.log('render');//读取状态const {isHot,wind} = this.state//解决changeWeather中this指向问题return <h1 onClick={this.changeWeather.bind(this)}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1>}//changeWeather调用几次? ———— 点几次调几次changeWeather(){//changeWeather放在哪里? ———— Weather的原型对象上,供实例使用//由于changeWeather是作为onClick的回调,所以不是通过实例调用的,是直接调用//类中的方法默认开启了局部的严格模式,所以changeWeather中的this为undefinedconsole.log('changeWeather');//获取原来的isHot值const isHot = this.state.isHot//严重注意:状态必须通过setState进行更新,且更新是一种合并,不是替换。this.setState({isHot:!isHot})console.log(this);//严重注意:状态(state)不可直接更改,下面这行就是直接更改!!!//this.state.isHot = !isHot //这是错误的写法}}//2.渲染组件到页面ReactDOM.render(<Weather/>,document.getElementById('test'))
简写形式代码
//1.创建组件class Weather extends React.Component{//初始化状态state = {isHot:false,wind:'微风'}render(){const {isHot,wind} = this.statereturn <h1 onClick={this.changeWeather.bind(this)}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1>}//自定义方法————要用赋值语句的形式+箭头函数changeWeather = ()=>{const isHot = this.state.isHotthis.setState({isHot:!isHot})}}//2.渲染组件到页面ReactDOM.render(<Weather/>,document.getElementById('test'))
setState(异步|同步)
setState异步|同步情况
setState处在同步的逻辑中, 异步更新状态,更新真实dom
setState处在异步的逻辑中, 同步更新状态,同步更新真实dom ```javascript
//count =1 //同步的逻辑中, 异步更新状态,更新真实dom handleAdd1 = ()=>{
this.setState({count:this.state.count+1})
console.log(this.state.count)//1
this.setState({
count:this.state.count+1
})
console.log(this.state.count)//1
}
handleAdd2 = ()=>{
//异步的逻辑中, 同步更新状态,同步更新真实dom
setTimeout(()=>{
this.setState({
count:this.state.count+1
})
console.log(this.state.count)//2
this.setState({
count:this.state.count+1
})
console.log(this.state.count)//3
},0)
}
<a name="AwmTt"></a>
## setState更新状态的2种写法
(1). setState(stateChange, [callback])------对象式的setState
1.stateChange为状态改变对象(该对象可以体现出状态的更改)
2.callback是可选的回调函数, 它在状态更新完毕、界面也更新后(render调用后)才被调用
(2). setState(updater, [callback])------函数式的setState
1.updater为返回stateChange对象的函数。
2.updater可以接收到state和props。
4.callback是可选的回调函数, 它在状态更新、界面也更新后(render调用后)才被调用。
总结: 1.对象式的setState是函数式的setState的简写方式(语法糖) 2.使用原则: (1).如果新状态不依赖于原状态 ===> 使用对象方式 (2).如果新状态依赖于原状态 ===> 使用函数方式 (3).如果需要在setState()执行后获取最新的状态数据, 要在第二个callback函数中读取
---
方式一 会因为异步更新导致连续调用的结果如下
```jsx
//设置count = 1
this.setState({
count: this.state.count + 1
})
console.log('count:', this.state.count) // 1
this.setState({
count: this.state.count + 1 // 1 + 1
})
console.log('count:', this.state.count) // 1
推荐方式二:这样连续调用this.setState 不会因为异步导致后者无法获取最新内容
// 方式一 : 对象形式,其实是方式二的语法糖
this.setState({name:'Change'});
// 方式二 : 函数形式
this.setState((state, props) => ({name:'Change'}));
// 方式一和二 都可以接受一个回调 用于state被修改后
this.setState({name:'Change'},()=>{
console.log('我被修改啦');
})
修改引用类型数据
比如数组,使用使用push,改变了数组但未实现响应式
hdClick(){
//深或浅复制再set
this.setState({
arr:[...this.state.arr,'new']
})
//替换第一位
let newArr = [...this.state.arr]
newArr.splice(1,0,'new')
this.setState({
arr:newArr
})
}
