React的内部数据用state表示,类似于Vue里的data
对于一个内部数据,我们只关注三件事:如何初始化,如何读,如何写
类组件
class Son extends React.Component {
constructor() {
super();
this.state = {
n: 0
};
}
add() {
// this.state.n += 1 为什么不行
this.setState({ n: this.state.n + 1 });
}
render() {
return (
<div className="Son">
儿子 n: {this.state.n}
<button onClick={() => this.add()}>+1</button>
<Grandson />
</div>
);
}
}
初始化
内部数据的初始化写在constructor里边,super()后边。声明一个this.state对象
读数据
this.state.n 就可以直接读数据。类似于类组件里读propsthis.props.xxx
写数据 : 最好使用this.setState(函数)
this.setState({ n:this.state.n +1})
在这里我们先调用一个add函数,在add函数里去修改。
首先明确,不能直接像这样修改this.state.n += 1。因为React里是没有数据监听和劫持的,只是单纯改变数据,React并不知道,不会更新UI。虽然这时n已经变了。
应该调用this.setState()函数。
参数是一个新的对象this.setState({ n:this.state.n +1})新对象的属性n的值是旧的+1。 注意,这里并没有修改原来的对象,也就是说,没有改this.state.n。而是生成一个新的对象。这叫数据不可变
setState异步更新UI:但是直接给它传一个新对象有时候会有bug。如我想打印出加1的值。
add() {
this.setState({ n: this.state.n + 1 });
console.log(this.state.n)
}
原来n=0,点击按钮+1,然后打印。但是我们发现,打印出来的还是0.
因为setState是异步的,当我们把一个新对象传给它的时候,告诉它我要把{n:0}改成{n:1},它不会马上更新state,而是等一会再去更新。等到什么时候呢?等到它的下一行执行完再去更新。所以立马读state会失败,读到的是旧state.所以打印的时候,state还是旧state。setState还没有更新。
给setState传一个函数: 为了避免混淆新旧state的问题,最好使用函数。
add() {
this.setState((state)=>{
return {n:state.n+1}
})
}
给this.setState传一个函数。这个函数的参数是旧state。return 一个新对象。看起来和直接传一个新对象一样。但是写成函数就可以明显的区分旧state和新state了。如果我想打印出新的值,就可以这样写:
add() {
this.setState((state)=>{
const n=state.n+1
console.log(n)
return {n:n}
})
}
函数组件
const Grandson = () => {
const [n, setN] = React.useState(0);
return (
<div className="Grandson">
孙子 n:{n}
<button onClick={() => setN(n + 1)}>+1</button>
</div>
);
};
初始化
const [n, setN] = React.useState(0);把初始值放在React.useState()里,它会返回一个数组,数组的第一项用来读,第二项用来写。没有第三项。
读数据
{n}
写数据
setN(n + 1)
注意
类组件里的setState不会马上改变state,等一会再改变。
函数组件里的setN()永远不会改变n,而是生成一个新的n
函数组件里没有this