咱們要認識到,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…