咱們要認識到,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中進行訪問。算法
使用npm run dev
命令運行,並在瀏覽器中打開查看吧。npm
咱們已經知道了如何初始化組件中的state值,那麼接下來咱們來看看,如何實現修改state的值瀏覽器
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
值,可是值得玩味的是,值的確是修改爲功了,可是,並無實時體如今界面上。這到底是怎麼回事呢?異步
這就要來看看,React中的setState
方法。函數
React對於setState
的定義爲請求React修改某個數據,而React的實現則是將對變量的修改放入一個修改隊列中,在一個循環以後進行批量更新結果(深刻點涉及VDom的更新機制)。因此,這裏會形成一個問題,就是setState
數據以後馬上進行讀取,可能你讀取到的數據,並不是是已經被更新過的有效值。性能
setState有三種修改數據的方式,讓咱們來一個一個嘗試。this
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
是採用異步隊列模式的。spa
如今出現了一個問題,若是咱們須要經過等待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> ); } }
最終顯示效果就是這樣的