咱们要认识到,React中的组件实际上是一个函数,因此state是函数内部的私有变量,外部其余组件或者方法都是没法直接访问到内部的state。 而state主要被设计用于维持组件内部私有状态。html
初始化state须要在class中constructor
进行。react
import React, { PureComponent } from 'react'
export default class index extends PureComponent {
constructor(props){
super(props)
this.state = {name:'demo react',time:new Date()}
}
render() {
return (
<div> Hello world React!{this.state.name} <p>组件生成时间:{this.state.time}</p> </div>
)
}
}
复制代码
在这个代码中,咱们初始化了name
,time
两个state值。一旦state初始化完成,咱们就能够在render中进行访问。webpack
使用npm run dev
命令运行,并在浏览器中打开查看吧。git
咱们已经知道了如何初始化组件中的state值,那么接下来咱们来看看,如何实现修改state的值github
import React, { PureComponent } from 'react'
export default class index extends PureComponent {
constructor(props){
super(props)
this.state = {name:'demo react',time:+new Date()}
}
handleUpdateName () {
this.state.time = (+new Date())
}
render() {
return (
<div> Hello world React!{this.state.name} <p>组件生成时间:{this.state.time}</p> <button onClick={this.handleUpdateName.bind(this)}>修改值</button> </div>
)
}
}
复制代码
有些动做快的同窗,第一个想法就是如此修改组件中的state
值,可是值得玩味的是,值的确是修改为功了,可是,并无实时体如今界面上。这到底是怎么回事呢?web
这就要来看看,React中的setState
方法。算法
React对于setState
的定义为请求React修改某个数据,而React的实现则是将对变量的修改放入一个修改队列中,在一个循环以后进行批量更新结果(深刻点涉及VDom的更新机制)。因此,这里会形成一个问题,就是setState
数据以后马上进行读取,可能你读取到的数据,并不是是已经被更新过的有效值。npm
setState有三种修改数据的方式,让咱们来一个一个尝试。浏览器
import React, { PureComponent } from 'react'
export default class index extends PureComponent {
constructor(props){
super(props)
this.state = {name:'demo react',time:+new Date()}
}
handleUpdateName () {
// this.state.time = (+new Date())
console.log('修改前的值',this.state.time)
this.setState({time:+new Date()})
console.log('修改后的值',this.state.time)
let that = this
setTimeout(function(){
console.log('当前state值',that.state.time)
})
}
render() {
return (
<div> Hello world React!{this.state.name} <p>组件生成时间:{this.state.time}</p> <button onClick={this.handleUpdateName.bind(this)}>修改值</button> </div>
)
}
}
复制代码
点击按钮,控制台输出了不一样的值,能够观察到setState
是采用异步队列模式的。异步
如今出现了一个问题,若是咱们须要经过等待setState
修改完成的值以后,应该如何处理?React为咱们的setState
提供了第二个参数callback
。
import React, { PureComponent } from 'react'
export default class index extends PureComponent {
constructor(props){
super(props)
this.state = {name:'demo react',time:+new Date()}
}
handleUpdateName () {
// this.state.time = (+new Date())
console.log('修改前的值',this.state.time)
this.setState({time:+new Date()},(function(){
console.log('当前state值',that.state.time)
})
console.log('修改后的值',this.state.time)
}
render() {
return (
<div> Hello world React!{this.state.name} <p>组件生成时间:{this.state.time}</p> <button onClick={this.handleUpdateName.bind(this)}>修改值</button> </div>
)
}
}
复制代码
再次运行,而且点击按钮。咱们能够看到控制台输出的值是跟第一个方法是一致的。
如今咱们来进行一次脑暴,可不能够直接修改state值呢?由于咱们在最先直接对state修改的时候,React并未关闭这个对象的set
方法。那么咱们能否直接经过修改state
来进行渲染呢?React中的一个方法为咱们解决了这个疑问。
import React, { PureComponent } from 'react'
export default class index extends PureComponent {
constructor(props){
super(props)
this.state = {name:'demo react',time:+new Date()}
}
handleUpdateName () {
console.log("修改前的值", this.state.time);
this.state.time = (+new Date())
console.log("修改后的值", this.state.time);
console.log("当前state值", this.state.time);
this.forceUpdate()
}
render() {
return (
<div> Hello world React!{this.state.name} <p>组件生成时间:{this.state.time}</p> <button onClick={this.handleUpdateName.bind(this)}>修改值</button> </div>
)
}
}
复制代码
上面这个代码仅仅用于脑暴,参考,不要在生产环境中使用,由于这个会形成React渲染算法与各类Hook失效,形成全局从新渲染。
在某些场景下面,咱们多是新的值是基于上一次的值推算而来,因此React提供了setState
传递进方法来进行推算处理。
import React, { PureComponent } from "react";
export default class index extends PureComponent {
constructor(props) {
super(props);
this.state = { name: "demo react", time: +new Date() };
}
handleUpdateName() {
console.log("修改前的值", this.state.time);
let that = this;
this.setState(oldData => {
return { time: oldData.time + 1000 };
});
console.log("修改后的值", this.state.time);
setTimeout(function() {
console.log("当前state值", that.state.time);
});
}
render() {
return (
<div> Hello world React!{this.state.name} <p>组件生成时间:{this.state.time}</p> <button onClick={this.handleUpdateName.bind(this)}>修改值</button> </div>
);
}
}
复制代码
最后说一点,就是setState
是浅拷贝,若是是结构比较深层的对象,不少同窗会采用JSON.string()
这种来进行深拷贝,这样的操做虽说是能够的,可是很是影响性能。
React推出了immutable
与15版本以后推出来的PureComponent
就是为了解决这些问题的。有兴趣的同窗能够搜索一下相关资料进行拓展阅读。
咱们知道,在函数中有带参数的方法,那么props其实就是传入方法中的参数。而且在React中props是只读属性。在使用场景上,是由父组件向子组件传递值的时候使用的。
咱们首先建立一个能够接收props
值的组件。
import React, { PureComponent } from "react";
export default class index extends PureComponent {
constructor(props) {
super(props);
}
render() {
return (
<div style={{'background':'#fefefe'}}> {this.props.value||'暂无数据'} </div>
);
}
}
复制代码
接着,咱们修改Index.js
引用这个组件。
import React, { PureComponent } from "react";
import Content from './content.js'
export default class index extends PureComponent {
constructor(props) {
super(props);
this.state = { name: "demo react", time: +new Date() };
}
handleUpdateName() {
this.setState({time:+new Date()})
}
render() {
return (
<div> Hello world React!{this.state.name} <p>组件生成时间:{this.state.time}</p> <button onClick={this.handleUpdateName.bind(this)}>修改值</button> <Content/> </div>
);
}
}
复制代码
这里你们有一点要注意,在React中,全部的组件名称第一个字母都必须大写,这是为了与html
标签区分出来。
如何向子组件传值呢?就像给html标签增长属性同样。
<Content value={'我设置了' + this.state.time}/>
复制代码
这样,组件内部能够经过props
读取到value
值了。不过React的组件传递中有一个颇有趣的属性children
,这个的用处传递组件包含的内容。
继续修改引入组件的代码,以下
// index.js
<Content value={'我设置了' + this.state.time} >主体Children</Content>
复制代码
import React, { PureComponent } from "react";
export default class index extends PureComponent {
constructor(props) {
super(props);
}
render() {
return (
<div style={{'background':'#fefefe'}}> {this.props.value||'暂无数据'},children:{this.props.children} </div>
);
}
}
复制代码
最终显示效果就是这样的
GitHub代码地址:github.com/yodfz/learn…