定义一个合适的State,是正确创建组件的第一步。State必须能代表一个组件UI呈现的完整状态集,即组件的任何UI改变,都可以从State的变化中反映出来;同时,State还必须是代表一个组件UI呈现的最小状态集,即State中的所有状态都是用于反映组件UI的变化,没有任何多余的状态,也不需要通过其他状态计算而来的中间状态。
组件中用到的一个变量是不是应该作为组件State,可以通过下面的4条依据进行判断:
- 这个变量是否是通过Props从父组件中获取?如果是,那么它不是一个状态。
- 这个变量是否在组件的整个生命周期中都保持不变?如果是,那么它不是一个状态。
- 这个变量是否可以通过其他状态(State)或者属性(Props)计算得到?如果是,那么它不是一个状态。
- 这个变量是否在组件的render方法中使用?如果不是,那么它不是一个状态。这种情况下,这个变量更适合定义为组件的一个普通属性
请务必牢记,并不是组件中用到的所有变量都是组件的状态!
注意:React在ES6的实现中,规定state在constructor中实现
正确定义State的方式如下:
(1)在constructor中实现state
(2)在constructor中通过bind绑定事件函数(事件函数是用来改变状态)
(3)在事件函数内部使用setState函数更改状态
(4)在组件中的render函数中使用该状态
(5)在组件上需要设置监听事件,去触发事件函数的执行
export default class extends Component {
constructor(arg){
super(arg)
this.state={
msg:"this.state中的数据"
}
this.fs=()=>{
this.state.msg="fs函数修改数据"
}
this.fs2=()=>{
console.log(this.state.msg)
}
}
render() {
return (
<p>this.state中修改变量值</p>
<h2>msg数据为:{this.state.msg}</h2>
<button onClick={this.fs}>修改数据</button>
<button onClick={this.fs2}>查看数据</button>
<hr />
</div>
)
}
2、setState设置状态
(1)语法:
setState(object nextState[, function callback])
(2)说明:
- setState是React事件处理函数中和回调函数中触发UI更新的主要方法。
- 不能在组件内部通过this.state修改状态,因为该状态会在调用setState()后被替换。
- setState()不一定是同步的,为了性能提升,React会批量执行state和DOM渲染。
- setState()总是会触发一次组件重绘,但可在shouldComponentUpdate()中实现一些条件渲染逻辑来解决。
当我们更新了msg的值以后,再次打印msg的值;会发现是更新之前的值,这时我们就需要使用setState函数中的参数(回调函数),在更新this.state以后再打印msg的值
同步设置多个状态时(不常用),可以在setState函数的第二个参数可以传递一个function回调函数,如下:
this.fs2=()=>{
this.setState( this.state,()=>{
console.log(this.state.msg)
})
}
state是异步函数还同步函数?
state在setimeout/原生函数中是同步函数,其余都是异步函数
3、State 与 Props 区别
- props 中的数据都是外界传递过来的
- state 中的数据都是组件私有的;(通过Ajax 获取回来的数据,一般都是私有数据)
- props 中的数据都是只读的,不能重新赋值
- state 中的数据都是可读可写的
- State定义在constructor内部,在super(props)代码后面;Props默认值定义在类(组件)的外部
除了State, 组件的Props也是和组件的UI有关的。他们之间的主要区别是:
当子组件的属性值是可变值时,采用状态上移:
状态上移通过属性将父组件的状态传递到子组件,那么父组件的状态发生变化时,子组件的属性也会改变
4、state/props 实现父子组件通信
- 子组件获取父组件整个组件进行传参
- 父组件在调用子组件时,传入一整个组件给子组件<Children parent={ this } />
- 父组件中定义一个方法getChildrenMsg(resulet, msg),用来获取子组件传来的值以及执行其他操作
- 子组件在通过this.props来获取到一整个组件this.props.parent 或者this.props[parent]
- 子组件调用父组件步骤2里定义的方法进行传值this.props.parent.getChildrenMsg(this,val)
举例:
父组件传值接子组件:父组件中定义状态this.state绑定函数修改状态中的值,记得最后刷新页面
父组件:
import React, { Component } from 'react'
import App3 from "./App3.jsx"
export default class App2 extends Component {
constructor(arg){
super(arg)
//第一步:设置状态
this.state={
name:"hello"
}
//第四步:定义修改值得函数
this.fn=()=>{
this.state.name="value change"
//记得刷新页面
this.setState(this.state)
}
}
render() {
return (
<div>
<p>App2父组件中</p>
//第二步:传值
<App3 name={this.state.name}></App3>
//第三步:绑定函数修改值
<button onClick={this.fn}>父组件修改子组件</button>
</div>
)
}
}
子组件:
import React, { Component } from 'react'
export default class extends Component {
render() {
return (
<div>
//取出父组件传得值
<div>子组件接受值:{this.props.name}</div>
</button>
</div>
)
}
}
子组件修改父组件得值:父组件传值时,添加参数组件得this;子组件中利用this调用父组件中的函数修改this.state状态中的值,并刷新页面
父组件:
import React, { Component } from 'react'
import App3 from "./App3.jsx"
export default class App2 extends Component {
constructor(arg){
super(arg)
//第一步:设置状态
this.state={
name:"hello"
}
this.value=this
//第五步:定义修改值的函数:修改状态中的值;记住刷新页面
this.change=(msg)=>{
this.state.name=msg
this.setState(this.state)
}
}
render() {
return (
<div>
<p>App2父组件中</p>
//第二步:传值,多传一个父组件的this
<App3 name={this.state.name} value={this.value}></App3>
</div>
)
}
}
子组件:
import React, { Component } from 'react'
export default class extends Component {
constructor(arg){
super(arg)
//第四步:定义修改值得函数====》利用接受到的父组件this调用父组件中的函数修改状态中的值
this.fm=()=>{
this.props.value.change("儿子修改了父亲的属性")
}
}
render() {
return (
<div>
//第三步:子组件接受值,并绑定修改值得函数
<div>子组件接受值:{this.props.name}</div>
<button onClick={this.fm}>子组件修改父组件</button>
</div>
)
}
}