React中state屬性案例詳解
通過之前的文章自定義組件,我們發(fā)現(xiàn)創(chuàng)建的類式組件里面會(huì)存在state屬性。在React中,state 是一個(gè)用于存儲組件內(nèi)部數(shù)據(jù)的特殊對象。每個(gè)React組件都可以包含自己的state,我們往往是通過修改state的值來驅(qū)動(dòng)React重新渲染組件。
由于函數(shù)式組件this指向的是undifind所以,函數(shù)式組件不存在state。
1)state案例
需求:點(diǎn)擊按鈕,切換標(biāo)題內(nèi)容
<script type="text/babel">
// 創(chuàng)建類式組件
class MyComponent extends React.Component {
render() {
console.log(this)
return (
<div>
<h1>內(nèi)容</h1>
<button>按鈕</button>
</div>
);
}
}
/*渲染組件到頁面*/
ReactDOM.render(<MyComponent/>, document.getElementById("demo"))
</script>我們是通過修改state的值來驅(qū)動(dòng)內(nèi)容的變化,那么我們想要使內(nèi)容變化,按鈕的點(diǎn)擊事件就是修改state的值。那怎么初始化state呢,我們知道,state是實(shí)例的屬性,所以我們想要初始化state的值需要在構(gòu)造器里面實(shí)現(xiàn)。
構(gòu)造器里面需要接受參數(shù),應(yīng)該是什么參數(shù)呢,通過查詢官網(wǎng),里面?zhèn)鬟f的參數(shù)為props,即:
class MyComponent extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h1>內(nèi)容</h1>
<button>按鈕</button>
</div>
);
}
}2)初始化state
有了構(gòu)造器我們就可以在構(gòu)造器里面初始化state的值了
class MyComponent extends React.Component {
constructor(props, context, updater) {
super(props, context, updater);
// 初始化state
this.state = {
count: 0
}
}
render() {
return (
<div>
<h1>{this.state.count}</h1>
<button>按鈕</button>
</div>
);
}
}此時(shí)就可以查看到state的值了:

3)原生JS事件綁定
原生的 JavaScript 綁定事件有多種方式,以下是其中一些常見的方法:
使用 addEventListener 方法: 這是一種推薦的方式,可以用于為一個(gè) DOM 元素添加事件監(jiān)聽器。它可以用于綁定多個(gè)事件處理函數(shù),而不會(huì)覆蓋之前綁定的處理函數(shù)。
var element = document.getElementById("myElement");
element.addEventListener("click", myFunction);內(nèi)聯(lián)事件處理函數(shù): 你可以將事件處理函數(shù)直接寫在 HTML 元素的屬性中,如 onclick、onmouseover 等。這不太推薦,因?yàn)閷?HTML 和 JavaScript 混合在一起可能會(huì)使代碼不夠清晰。
<button onclick="myFunction()">點(diǎn)擊我</button>
DOM 屬性方式: 你可以直接為 DOM 元素的事件處理屬性分配函數(shù),這與內(nèi)聯(lián)事件處理函數(shù)類似,但是更清晰一些。
var element = document.getElementById("myElement");
element.onclick = myFunction;4)React事件綁定
上面提到了原生的JS事件綁定方式,除了內(nèi)斂事件處理函數(shù)其他都需要操作DOM,而我們的React是不需要操作DOM的,因此我們使用內(nèi)斂事件處理函數(shù)對元素添加事件綁定。
class MyComponent extends React.Component {
constructor(props, context, updater) {
super(props, context, updater);
this.state = {
count: 0
}
}
render() {
return (
<div>
<h1>{this.state.count}</h1>
<button οnclick="increment()">按鈕</button>
</div>
);
}
}
//注冊點(diǎn)擊事件
function increment() {
console.log("按鈕被點(diǎn)擊了")
}上面通過
onClick="increment()"給按鈕注冊了點(diǎn)擊事件
通過上面的注冊事件我們發(fā)現(xiàn)控制臺報(bào)錯(cuò)了

根據(jù)錯(cuò)誤提示,告訴我們在嘗試使用 onclick 事件處理屬性時(shí)出現(xiàn)錯(cuò)誤,提示是否想使用 onClick。所以我們把onclick變成onClick。
render() {
return (
<div>
<h1>{this.state.count}</h1>
<button onClick="increment()">按鈕</button>
</div>
);
}但是發(fā)現(xiàn)還是報(bào)錯(cuò)了

報(bào)錯(cuò)的意思是期望 onClick 事件監(jiān)聽器是一個(gè)函數(shù),但實(shí)際上它是一個(gè)字符串類型的值。我們嘗試使用JSX的表達(dá)式將函數(shù)賦值給onClick事件
<button onClick={increment()}>按鈕</button>此時(shí)我們發(fā)現(xiàn),我們還沒有點(diǎn)擊按鈕,一刷新網(wǎng)頁,控制臺立馬打印了按鈕被點(diǎn)擊了這句話,也就是說在刷新網(wǎng)頁的時(shí)候increment()立即執(zhí)行了,點(diǎn)擊按鈕卻得不到我們想要的結(jié)果。
我們再來分析一下onClick={increment()},這里面其實(shí)是將increment()執(zhí)行結(jié)束之后的返回值賦值給onClick,而不是將函數(shù)賦值給onClick,所以increment()立即執(zhí)行,然后將返回的undefined賦值給onClick,所以點(diǎn)擊按鈕當(dāng)然沒有作用,我們能做的就是把increment函數(shù)本身賦值給onClick:
<button onClick={increment}>按鈕</button>此時(shí)點(diǎn)擊按鈕成功打印結(jié)果,控制臺也不存在報(bào)錯(cuò)。
5)類中方法this指向
解決了點(diǎn)擊事件,我們下面的目標(biāo)就修改state里面的count,我們能直接在increment函數(shù)里面修改嗎?組件的實(shí)例并不是我們創(chuàng)建的,而且函數(shù)在組件(類)的外面,increment的this指向的是undefined,也就是說increment函數(shù)根本訪問不到組件的this,從而也就訪問不到組件的state。
我們可以把increment函數(shù)寫在類組件里面,作為類的一般方法。
class MyComponent extends React.Component {
constructor(props, context, updater) {
super(props, context, updater);
this.state = {
count: 0
}
}
render() {
return (
<div>
<h1>{this.state.count}</h1>
<button onClick={increment}>按鈕</button>
</div>
);
}
// 注意作為一般方法,不需要使用function修飾
increment() {
console.log("按鈕被點(diǎn)擊了"+this.state.count)
}
}此時(shí)我們發(fā)現(xiàn)控制臺又報(bào)錯(cuò)了,提示我們increment未定義,可是我們已經(jīng)定義了的

我們實(shí)現(xiàn)的increment函數(shù)作為一般方法,可以通過類的實(shí)例調(diào)用,而onClick={increment}根本訪問不到,所以修改成下面:
<button onClick={this.increment}>按鈕</button>此時(shí)報(bào)錯(cuò)解決了,但是我們點(diǎn)擊按鈕的時(shí)候,報(bào)錯(cuò)又接踵而至:

根據(jù)提示我們發(fā)現(xiàn)state讀取不到,可是我們的state就是掛載在this上面的屬性,怎么會(huì)讀取不到呢,我們通過在increment函數(shù)打印this查看:
increment() {
console.log(this)
console.log("按鈕被點(diǎn)擊了"+this.state.count)
}我們發(fā)現(xiàn)打印的結(jié)果是undefined,這令我們很奇怪,方法定義在類里面,怎么會(huì)訪問不到this呢,而同樣為類的方法render卻可以訪問到this呢?
我們再回顧一下創(chuàng)建類式組件以及渲染類式組件的過程,我們定義組件重寫了render方法,返回VDOM,而React想要渲染DOM需要?jiǎng)?chuàng)建組件的實(shí)例,然后**通過實(shí)例調(diào)用render**方法。我們知道類里面的方法是掛載到原型對象上的,只有通過類的實(shí)例調(diào)用方法才能訪問到this,而我們創(chuàng)建的組件實(shí)例并不是有我們創(chuàng)建的,我們只是把increment函數(shù)賦值給onClick,所以increment可能不是通過實(shí)例去調(diào)用的。
6)類中方法this指向案例
我們創(chuàng)建一個(gè)類,類里面有speak方法,用于打印this
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
speak(){
console.log(this)
}
}創(chuàng)建實(shí)例,調(diào)用方法
const p=new Person('jvyou',22)
p.speak()此時(shí)成功打印出來p的this,說明通過類的實(shí)例調(diào)用類里面的方法,方法里面的this就是指向?qū)嵗?/p>

我們將p.speak賦值給其他變量嘗試直接調(diào)用試試:
const s = p.speak s()
輸出的結(jié)果卻是undefined,這個(gè)屬于直接調(diào)用,原本的this應(yīng)該是window,但是由于嚴(yán)格模式下就是undefind
通過這個(gè)案例我們再回顧以下我們的代碼:
<button onClick={this.increment}>按鈕</button>我們將this.increment賦值給onClick,在點(diǎn)擊按鈕的時(shí)候React會(huì)直接調(diào)用onClick,根本不是通過組件的實(shí)例調(diào)用的,所以根本訪問不到組件的this,所以也訪問不到組件的state。
7)解決this指向undefined
我們知道可以通過bind方法給函數(shù)綁定this,我們可以在構(gòu)造函數(shù)里面訪問到this,我們可以通過在構(gòu)造函數(shù)里面給increment方法綁定實(shí)例的this,再將綁定成功的新的函數(shù)掛載到對象的屬性上。
constructor(props, context, updater) {
super(props, context, updater);
this.state = {
count: 0
}
this.increment = this.increment.bind(this)
}
this.increment.bind(this)綁定this之后返回一個(gè)新的函數(shù),此時(shí)函數(shù)內(nèi)部的this指向的就是創(chuàng)建的對象再將返回的函數(shù)賦值給
this.increment,作為屬性掛載到對象上。
此時(shí)再點(diǎn)擊按鈕,成功打印出組件的this,且發(fā)現(xiàn)increment也變成組件屬性了,且原型鏈上面也存在increment方法,屬性上的increment是通過原型鏈上的increment綁定this得來的,因此onClick={this.increment}是將屬性上的increment賦值給onClick。
8)修改state
通過上面的方式我們就可以在方法里面修改this.state:
increment() {
this.state.count++
console.log("按鈕被點(diǎn)擊了" + this.state.count)
}但是我們發(fā)現(xiàn)點(diǎn)擊了按鈕不報(bào)錯(cuò),count的值也一直為0不改變
這是因?yàn)?code>state不能直接更改,需要使用React的內(nèi)置API。
我們可以通過打印組件的this,在原型鏈上找到API:setState,所以可以直接通過this訪問即可

increment() {
const c = this.state.count + 1
this.setState({count: c})
console.log("按鈕被點(diǎn)擊了" + this.state.count)
}此時(shí)成功解決。但是在實(shí)現(xiàn)的時(shí)候使用了const c = this.state.count + 1,嫩不能改成const c = this.state.count++呢,是不能的,因?yàn)檫@二樣會(huì)直接修改state的值。
state存在多個(gè)屬性怎么修改呢
constructor(props, context, updater) {
super(props, context, updater);
this.state = {
count: 0,
name: '橘柚'
}
this.increment = this.increment.bind(this)
}上面代碼state里面存在兩個(gè)屬性
increment() {
const c = this.state.count + 1
this.setState({count: c})
}這里面只修改了count,但不會(huì)影響到name
9)state的簡寫
簡化state
我們在上面初始化state的時(shí)候是在構(gòu)造器里面實(shí)現(xiàn)的,但是我們知道,類里面可以直接定義類的屬性,而且可以直接給屬性賦值,所以我們就不需要在構(gòu)造器里面初始化state,直接修改成:
class MyComponent extends React.Component {
//初始化state,直接作為類組件的屬性定義
state = {
count: 0,
name: '橘柚'
}
// 構(gòu)造器
constructor(props, context, updater) {
super(props, context, updater);
this.increment = this.increment.bind(this)
}
...省略render和increment
}簡化事件
我們知道increment函數(shù)在MyComponent原型鏈上不通過實(shí)例調(diào)用會(huì)導(dǎo)致this指向丟失,所以我們通過bind掛載this解決,即this.increment = this.increment.bind(this),但是我們知道箭頭函數(shù)的 this 指向是與普通函數(shù)不同的。箭頭函數(shù)的 this 指向是繼承自包含它的最近的父級(詞法作用域)函數(shù)的 this 值,而不是動(dòng)態(tài)綁定的。所以只需要將increment變成箭頭函數(shù),在創(chuàng)建實(shí)例的時(shí)候increment的this自己就會(huì)指向?qū)嵗?,無需再次綁定。
increment = () => {
const c = this.state.count + 1
this.setState({count: c})
console.log("按鈕被點(diǎn)擊了" + this.state.count)
}此時(shí)我們打印this,也能在組件的屬性上面找到increment。

一開始我們添加構(gòu)造器是為了初始化state以及為事件綁定this,現(xiàn)在全部解決了,構(gòu)造器也就不用存在了,所以最后的代碼如下:
class MyComponent extends React.Component {
state = {
count: 0,
name: '橘柚'
}
increment = () => {
const c = this.state.count + 1
this.setState({count: c})
console.log("按鈕被點(diǎn)擊了" + this.state.count)
}
render() {
return (
<div>
<h1>{this.state.count}{this.state.name}</h1>
<button onClick={this.increment}>按鈕</button>
</div>
);
}
}10)setState 擴(kuò)展
對象式setState
我們可以使用 setState 來更新組件的狀態(tài),但是 setState 有兩種常見的寫法,上面我們一直用的是傳遞一個(gè)對象,即:
this.setState({ count: this.state.count + 1 });這種寫法直接傳遞一個(gè)新的狀態(tài)對象給 setState。React會(huì)將新狀態(tài)與當(dāng)前狀態(tài)合并,并在后續(xù)的更新周期中應(yīng)用這個(gè)新狀態(tài)。
但其實(shí)setState還有第二個(gè)參數(shù):
setState( stateChange , [callback] )
stateChange :狀態(tài)改變對象? callback:可選回調(diào)函數(shù),它在狀態(tài)更新完畢,render調(diào)用后,才被調(diào)用
這個(gè)回調(diào)有什么用呢,我們先看一個(gè)案例:
export default class Count extends Component {
state = {
count: 0
}
increment = () => {
const {count} = this.state
this.setState({count: count + 1})
console.log("@count:", this.state.count)
}
render() {
return (
<div>
<h1>當(dāng)前Count:{this.state.count}</h1>
<button onClick={this.increment}>+1</button>
</div>
)
}
}當(dāng)我們點(diǎn)擊了“+1”的按鈕之后,頁面展示的效果確實(shí)是1,但是打印的結(jié)果卻是0,我們在打印count的時(shí)候已經(jīng)執(zhí)行 this.setState({count: count + 1})進(jìn)行狀態(tài)更新了,為什么還是0呢?那是因?yàn)?code>setState 可能是異步的,所以在讀取 this.state 之前不應(yīng)該依賴于它的值。

如果需要在狀態(tài)更新后執(zhí)行一些操作,可以將這些操作放在 setState 的回調(diào)函數(shù)中:
increment = () => {
const {count} = this.state
this.setState({count: count + 1}, () => {
console.log("@count:", this.state.count)
})
}函數(shù)式setState
傳遞一個(gè)更新函數(shù):
this.setState((prevState, props ) => {
return { count: prevState.count + 1 };
} , [callback]);這種寫法將狀態(tài)的更新邏輯封裝在一個(gè)函數(shù)中,并接受參數(shù) prevState和props,prevState代表當(dāng)前狀態(tài)的先前值。
這兩種寫法的選擇取決于你的需求和使用情境。通常情況下,使用更新函數(shù)的方式更加安全,因?yàn)樗梢源_?;诋?dāng)前狀態(tài)來計(jì)算新狀態(tài),避免了潛在的競態(tài)條件和不一致性。另外,使用更新函數(shù)的方式也適用于異步更新狀態(tài)的情況。
到此這篇關(guān)于React中state屬性的文章就介紹到這了,更多相關(guān)React state屬性內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
React報(bào)錯(cuò)map()?is?not?a?function詳析
這篇文章主要介紹了React報(bào)錯(cuò)map()?is?not?a?function詳析,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-08-08
react框架next.js學(xué)習(xí)之API?路由篇詳解
這篇文章主要為大家介紹了react框架next.js學(xué)習(xí)之API?路由篇詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09
react?component?function組件使用詳解
這篇文章主要為大家介紹了react?component?function組件的使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11
React 使用recharts實(shí)現(xiàn)散點(diǎn)地圖的示例代碼
這篇文章主要介紹了React 使用recharts實(shí)現(xiàn)散點(diǎn)地圖的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-12-12

