React?組件中?State?的定義、使用及正確使用方式
前言
在 React 應(yīng)用開發(fā)中,state
是組件內(nèi)部用來存儲和管理數(shù)據(jù)的關(guān)鍵概念。它允許組件根據(jù)不同的狀態(tài)展示不同的 UI。本文將詳細(xì)介紹 state
的定義、使用方式以及如何正確地更新 state
,幫助開發(fā)者更好地理解和運(yùn)用這一核心特性。
1.1 state及其特點(diǎn)
State 與 props 類似,但是 state 是私有的,并且完全受控于當(dāng)前組件
不要直接修改state:構(gòu)造函數(shù)是唯一可以給 this.state
賦值的地方。
state更新可能是異步的:出于性能考慮,React 可能會把多個 setState()
調(diào)用合并成一個調(diào)用。
state更新會被合并:當(dāng)你調(diào)用 setState()
的時候,React 會把你提供的對象合并到當(dāng)前的 state
1.2 state的定義和使用
目前react中的狀態(tài)有兩種使用方式:
1.2.1 es6的類 - 構(gòu)造函數(shù)
src/index.js
import React from 'react' import ReactDOM from 'react-dom/client' ? // 引入時,后綴名可以省略,可以在webpack中配置 // import App from './01-App-parent-child' // import App from './02-App-parent-child-value' // import App from './03-App-parent-child-value-default' // import App from './04-App-parent-child-value-default-type' // import App from './05-App-props-children' // import App from './06-App-mutiple-props-children' // import App from './07-App-mouse-tracker' // import App from './08-App-render-props' import App from './09-App-state-es6' ? const root = ReactDOM.createRoot(document.getElementById('root')) ? root.render(<App />)
src/09-App-state-es6.jsx
import React, { Component } from 'react'; ? /** * ES6 規(guī)定,子類必須在constructor()方法中調(diào)用super(),否則就會報(bào)錯。 這是因?yàn)樽宇愖约旱膖his對象,必須先通過父類的構(gòu)造函數(shù)完成塑造, 得到與父類同樣的實(shí)例屬性和方法,然后再對其進(jìn)行加工,添加子類自己的實(shí)例屬性和方法。 如果不調(diào)用super()方法,子類就得不到自己的this對象。 ? ES5 的繼承機(jī)制,是先創(chuàng)造一個獨(dú)立的子類的實(shí)例對象, 然后再將父類的方法添加到這個對象上面,即“實(shí)例在前,繼承在后”。 ES6 的繼承機(jī)制,則是先將父類的屬性和方法,加到一個空的對象上面, 然后再將該對象作為子類的實(shí)例,即“繼承在前,實(shí)例在后” */ class App extends Component { // es6的類 - 構(gòu)造函數(shù) constructor (props) { super(props) // 調(diào)用父類的constructor(props) this.state = { // 添加子類自己的實(shí)例屬性和方法,在react中 state作為初始化狀態(tài)的屬性 date: new Date() } } render() { return ( <div> 現(xiàn)在的時間是:{ this.state.date.toLocaleDateString() + this.state.date.toLocaleTimeString() } </div> ); } } ? export default App;
1.2.2 es7的類 - 屬性初始化器
src/index.js
import React from 'react' import ReactDOM from 'react-dom/client' ? // 引入時,后綴名可以省略,可以在webpack中配置 // import App from './01-App-parent-child' // import App from './02-App-parent-child-value' // import App from './03-App-parent-child-value-default' // import App from './04-App-parent-child-value-default-type' // import App from './05-App-props-children' // import App from './06-App-mutiple-props-children' // import App from './07-App-mouse-tracker' // import App from './08-App-render-props' // import App from './09-App-state-es6' import App from './10-App-state-es7' ? const root = ReactDOM.createRoot(document.getElementById('root')) ? root.render(<App />)
src/10-App-state-es7.jsx
import React, { Component } from 'react'; ? // 推薦寫法 class App extends Component { state = { // es7 類的屬性 date: new Date() } render() { return ( <div> 現(xiàn)在的時間是:{ this.state.date.toLocaleDateString() + this.state.date.toLocaleTimeString() }!??! </div> ); } } ? export default App;
1.3 如何正確的修改state
setState()
將對組件 state 的更改排入隊(duì)列,并通知 React 需要使用更新后的 state 重新渲染此組件及其子組件。這是用于更新用戶界面以響應(yīng)事件處理器和處理服務(wù)器數(shù)據(jù)的主要方式.
將 setState()
視為請求而不是立即更新組件的命令。為了更好的感知性能,React 會延遲調(diào)用它,然后通過一次傳遞更新多個組件。
setState()
并不總是立即更新組件。它會批量推遲更新。這使得在調(diào)用 setState()
后立即讀取 this.state
成為了隱患。為了消除隱患,請使用 componentDidUpdate
或者 setState
的回調(diào)函數(shù)(setState(updater, callback)
),這兩種方式都可以保證在應(yīng)用更新后觸發(fā)。
記住修改狀態(tài)的三大原則:
不要直接修改 State
state = { a: 10 } this.state.a = 100 // ?
state 的更新可能是異步的
state = { a: 10 } this.setState({a: this.state.a + 1 }) this.setState({a: this.state.a + 1 }) this.setState({a: this.state.a + 1 }) console.log(this.state.a) // 10
state 的更新會被合并
1.4 this.setState()方法及其特點(diǎn)
setState()
會對一個組件的 state
對象安排一次更新。當(dāng) state 改變了,該組件就會重新渲染。
setState()
可以添加兩個參數(shù),
setState()
的第二個參數(shù)為可選的回調(diào)函數(shù),它將在 setState
完成合并并重新渲染組件后執(zhí)行
1.4.1 傳遞函數(shù)
參數(shù)一為帶有形式參數(shù)的 updater
函數(shù):
this.setState((state, props) => stateChange[, callback] )
src/index.js
import React from 'react' import ReactDOM from 'react-dom/client' ? // 引入時,后綴名可以省略,可以在webpack中配置 // import App from './01-App-parent-child' // import App from './02-App-parent-child-value' // import App from './03-App-parent-child-value-default' // import App from './04-App-parent-child-value-default-type' // import App from './05-App-props-children' // import App from './06-App-mutiple-props-children' // import App from './07-App-mouse-tracker' // import App from './08-App-render-props' // import App from './09-App-state-es6' // import App from './10-App-state-es7' import App from './11-App-setState-function' ? const root = ReactDOM.createRoot(document.getElementById('root')) ? root.render(<App />)
src/11-App-setState-function.jsx
import React, { Component } from 'react'; ? class App extends Component { state = { count: 100 } render() { return ( <div> { this.state.count } <button onClick={ () => { this.setState((state, props) => { console.log(state, props) return { count: state.count + 1 } }) this.setState((state, props) => { console.log(state, props) return { count: state.count + 1 } }) this.setState((state, props) => { console.log(state, props) return { count: state.count + 1 } }) } }>加</button> </div> ); } } ? export default App
updater 函數(shù)中接收的
state
和props
都保證為最新。updater 的返回值會與state
進(jìn)行淺合并。
1.4.2 傳遞對象
src/index.js
import React from 'react' import ReactDOM from 'react-dom/client' ? // 引入時,后綴名可以省略,可以在webpack中配置 // import App from './01-App-parent-child' // import App from './02-App-parent-child-value' // import App from './03-App-parent-child-value-default' // import App from './04-App-parent-child-value-default-type' // import App from './05-App-props-children' // import App from './06-App-mutiple-props-children' // import App from './07-App-mouse-tracker' // import App from './08-App-render-props' // import App from './09-App-state-es6' // import App from './10-App-state-es7' // import App from './11-App-setState-function' import App from './12-App-setState-object' ? const root = ReactDOM.createRoot(document.getElementById('root')) ? root.render(<App />)
src/12-App-setState-object.jsx
import React, { Component } from 'react'; // 為什么? // const obj = { a: 100 } // es6 中對象合并 // const newObj = Object.assign(obj, {a: 100 + 1}, {a: 100 + 1}, {a: 100 + 1}) // console.log(newObj) // { a: 101 } ? class App extends Component { state = { count: 10 } render() { return ( <div> { this.state.count } <button onClick={ () => { this.setState({ count: this.state.count + 1 }) this.setState({ count: this.state.count + 1 }) this.setState({ count: this.state.count + 1 }) console.log(this.state.count) } }>加</button> </div> ); } } ? export default App;
這種形式的
setState()
是異步的,并且在同一周期內(nèi)會對多個setState
進(jìn)行批處理,相當(dāng)于
Object.assign( prevState, {count: this.state.count + 1}, {count: this.state.count + 1}, ... )
后調(diào)用的
setState()
將覆蓋同一周期內(nèi)先調(diào)用setState
的值,因此商品數(shù)僅增加一次。如果后續(xù)狀態(tài)取決于當(dāng)前狀態(tài),建議使用 updater 函數(shù)的形式代替(前面案例已經(jīng)實(shí)現(xiàn))?;蛘咴诘诙€參數(shù)中再繼續(xù)操作。
src/index.js
import React from 'react' import ReactDOM from 'react-dom/client' ? // 引入時,后綴名可以省略,可以在webpack中配置 // import App from './01-App-parent-child' // import App from './02-App-parent-child-value' // import App from './03-App-parent-child-value-default' // import App from './04-App-parent-child-value-default-type' // import App from './05-App-props-children' // import App from './06-App-mutiple-props-children' // import App from './07-App-mouse-tracker' // import App from './08-App-render-props' // import App from './09-App-state-es6' // import App from './10-App-state-es7' // import App from './11-App-setState-function' // import App from './12-App-setState-object' import App from './13-App-setState-callback' ? const root = ReactDOM.createRoot(document.getElementById('root')) ? root.render(<App />)
src/13-App-setState-callback.jsx
import React, { Component } from 'react'; ? ? class App extends Component { state = { count: 10 } render() { return ( <div> { this.state.count } <button onClick={ () => { this.setState({ count: this.state.count + 1 }, () => { this.setState({ count: this.state.count + 1 }, () => { this.setState({ count: this.state.count + 1 }) }) }) console.log(this.state.count) // 10 } }>加</button> </div> ); } } ? export default App;
思考題:
總結(jié)
通過本文的介紹,我們了解了 state
在 React 組件中的重要性,以及如何在 ES6 和 ES7 類組件中定義和使用 state
。同時,我們還探討了正確更新 state
的方法,包括使用 setState()
方法時需要注意的事項(xiàng)。遵循這些最佳實(shí)踐,可以幫助我們避免常見的陷阱,提高應(yīng)用的性能和可靠性。
到此這篇關(guān)于React 組件中 State 的定義、使用及正確更新方式的文章就介紹到這了,更多相關(guān)React State 組件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
React?hook實(shí)現(xiàn)簡單的websocket封裝方式
這篇文章主要介紹了React?hook實(shí)現(xiàn)簡單的websocket封裝方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-09-09React實(shí)現(xiàn)點(diǎn)擊切換組件效果
這篇文章主要為大家詳細(xì)介紹了如何基于React實(shí)現(xiàn)點(diǎn)擊切換組件效果,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的小伙伴可以學(xué)習(xí)一下2023-08-08React之如何在Suspense中優(yōu)雅地請求數(shù)據(jù)
Suspense 是 React 中的一個組件,直譯過來有懸掛的意思,能夠?qū)⑵浒漠惒浇M件掛起,直到組件加載完成后再渲染,本文詳細(xì)介紹了如何在Suspense中請求數(shù)據(jù),感興趣的小伙伴可以參考閱讀本文2023-04-04react中的useImperativeHandle()和forwardRef()用法
這篇文章主要介紹了react中的useImperativeHandle()和forwardRef()用法,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-08-08React利用props的children實(shí)現(xiàn)插槽功能
React中并沒有vue中的?slot?插槽概念?不過?可以通過props.children?實(shí)現(xiàn)類似功能,本文為大家整理了實(shí)現(xiàn)的具體方,需要的可以參考一下2023-07-07react實(shí)現(xiàn)一個優(yōu)雅的圖片占位模塊組件詳解
這篇文章主要給大家介紹了關(guān)于react如何實(shí)現(xiàn)一個還算優(yōu)雅的占位模塊圖片組件的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2017-10-10