react函數(shù)組件useState異步,數(shù)據(jù)不能及時(shí)獲取到的問題
react useState異步,數(shù)據(jù)不能獲取到
useState() 屬于異步函數(shù),在useState() 第一次存儲(chǔ)的時(shí)候,值會(huì)存儲(chǔ)不上
因?yàn)閞eact中state的更新是異步的,我們setState后,react不會(huì)立刻對(duì)值進(jìn)行改變,而是將其暫時(shí)放入pedding隊(duì)列中。react會(huì)合并多個(gè)state,然后值render一次,所以不要在循環(huán)中使用useState,它有可能只render最后一次set值,但是當(dāng)傳入一個(gè)函數(shù)時(shí),函數(shù)就會(huì)被放入一個(gè)隊(duì)列中,然后按照順序執(zhí)行。
問題
const Dva = () => { const [arr, setArr] = useState([0]) // 兩個(gè)回調(diào)函數(shù),第一個(gè)回調(diào)函數(shù)完成后,會(huì)將返回結(jié)果作為參數(shù),傳入第二個(gè)參數(shù) const handleClick = () => { Promise.resolve().then(() => { setArr([...arr, 1]); }) .then(() => { setArr([...arr, 2]); }) } useEffect(() => { console.log(arr) }, [arr]); return ( <> <div> <button onClick={handleClick}>change</button> </div> </> ) }
輸出:
解決方法一
使用回調(diào)方式傳參
const handleClick = () => { Promise.resolve().then(() => { setArr([...arr, 1]); }).then(() => { setArr(preStae => [...preStae, 2]) }) } useEffect(() => { console.log(arr) }, [arr]);
輸出:
react中useState的使用及注意事項(xiàng)
基本使用
useState是 react 提供的一個(gè)定義響應(yīng)式變量的 hook 函數(shù),基本語(yǔ)法如下:
const [count, setCount] = useState(initialCount)
- 它返回一個(gè)狀態(tài)和一個(gè)修改狀態(tài)的方法,狀態(tài)需要通過這個(gè)方法來進(jìn)行修改;
- initialCount 是我們傳入的一個(gè)初始狀態(tài),它是惰性的,我們可以通過傳一個(gè)函數(shù)來返回一個(gè)值當(dāng)作初始狀態(tài),并且這個(gè)函數(shù)只會(huì)在初始渲染時(shí)執(zhí)行一次;
const [count, setCount] = useState(() => { const initialCount = someExpensiveComputation(); return initialCount })
接下來把定義好的狀態(tài)運(yùn)用到頁(yè)面:
import { useState } from 'react' function App() { const [count, setCount] = useState(0) const handleClick = () => { setCount(count + 1) // 傳入一個(gè)函數(shù),更新的值是基于之前的值來執(zhí)行 // setCount(count => count + 1) } return ( <div> <h4>count: {count}</h4> <button onClick={ handleClick }>點(diǎn)擊更新狀態(tài)</button> </div> ) }
頁(yè)面渲染完成后,我們可以看到 count的值是 0,當(dāng)我們點(diǎn)擊按鈕時(shí),會(huì)將 count的值加 1,頁(yè)面也同時(shí)更新;
了解完基礎(chǔ)用法后,我們可以思考幾個(gè)問題;
- setCount修改值時(shí)它是同步還是異步?
- 連續(xù)調(diào)用 setCount會(huì)發(fā)生什么?
第一個(gè)問題:setCount修改值時(shí)它是同步還是異步?
const handleClick = () => { console.log("value1: ", count) setCount(count => count + 1) console.log("value2: ", count) }
從圖中我們可以看出,頁(yè)面的值是更新了,但是控制臺(tái)打印的是之前的值,這是不是也表示 setCount是異步的呢?我們換一種方法,用異步來修改狀態(tài);
const handleClick = () => { console.log("value1: ", count) setTimeout(() => { setCount(count => count + 1) console.log("value2: ", count) }, 0) }
顯然,異步修改狀態(tài)跟同步修改狀態(tài)的結(jié)果是一致的,這也表明了 setCount 是異步更新的;那我們要怎么拿到更新后的值呢,我們可以用另外一個(gè) hook 函數(shù) useRef,代碼如下:
function App() { const [count, setCount] = useState(0) const countRef = useRef(count) countRef.current = count const handleClick = () => { setCount(count => count + 1) console.log("value3: ", count) setTimeout(() => { console.log(countRef.current) }, 0) } return ( <div> <h4>count: {count}</h4> <button onClick={handleClick}>點(diǎn)擊更新狀態(tài)</button> </div> ) }
從圖中我們可以看出,我們已經(jīng)拿到了更新之后的值,useRef不僅可以用于訪問 DOM 節(jié)點(diǎn),也可以用來表示一個(gè)容器,current屬性可以保存任何值,而且useRef返回的對(duì)象會(huì)在整個(gè)生命周期內(nèi)保持;
第二個(gè)問題:連續(xù)調(diào)用 setCount會(huì)發(fā)生什么?
(1)傳入一個(gè)基于狀態(tài)的值
const handleClick = () => { console.log("value1: ", count) setCount(count + 1) console.log("value2: ", count) setCount(count + 1) console.log("value3: ", count) }
從圖片可以看出,如果我們傳入的是一個(gè)普通值,他只會(huì)進(jìn)行最后一次更新;
(2)傳入一個(gè)函數(shù)
const handleClick = () => { console.log("value1: ", count) setCount(count => count + 1) console.log("value2: ", count) setCount(count => count + 1) console.log("value3: ", count) }
可以看出,傳入一個(gè)函數(shù)的話,它會(huì)進(jìn)行兩次賦值,因?yàn)樗碌闹凳腔谥暗闹祦韴?zhí)行,所以在開發(fā)中推薦使用函數(shù)傳入的形式進(jìn)行修改;
注意事項(xiàng)
1、復(fù)雜變量的修改
對(duì)于復(fù)雜類型的變量我們修改時(shí)需要重新定義,在原來數(shù)據(jù)的基礎(chǔ)上修改不會(huì)引起組件的重新渲染,因?yàn)?React 組件的更新機(jī)制只進(jìn)行淺對(duì)比,也就是更新某個(gè)復(fù)雜類型數(shù)據(jù)時(shí)只要它的引用地址沒變,就不會(huì)重新渲染組件;舉個(gè)例子
function App() { const [arr, setArr] = useState([1]) const pushData = () => { arr.push(4) setArr(arr) } return ( <div> <h4>{arr.join("-")}</h4> <button onClick={pushData}>點(diǎn)擊添加數(shù)組</button> </div> ) }
上面的代碼在點(diǎn)擊按鈕時(shí),視圖不會(huì)發(fā)生變化,但是 arr的值是變化了,如果想修改這個(gè)數(shù)組,需要重新定義一個(gè)數(shù)組來修改,在原數(shù)組上的修改不會(huì)引起組件的重新渲染,React 組件的更新機(jī)制對(duì)只進(jìn)行淺對(duì)比,也就是更新某個(gè)復(fù)雜類型數(shù)據(jù)時(shí)只要它的引用地址沒變,就不會(huì)重新渲染組件;
const pushData = () => { setArr([...arr, 4]) }
2、異步操作獲取更新的值
在類組件里面,修改值時(shí)異步操作可以拿到更新后的值,但是在函數(shù)組件,異步獲取是拿不到更新后的值的,舉個(gè)例子對(duì)比一下:
類組件
class App extends React.Component { constructor() { super() this.state = { count: 0 } } handleClick = () => { this.setState({ count: this.state.count + 1 }) console.log(this.state.count) setTimeout(() => { console.log(this.state.count) }) } render() { return ( <> <h4>count: {this.state.count}</h4> <button onClick={this.handleClick}>點(diǎn)擊更新狀態(tài)</button> </> ); } }
函數(shù)組件
function App() { const [count, setCount] = useState(0) const handleClick = () => { setCount(count => count + 1) console.log("value1: ", count) setTimeout(() => { console.log("value2: ", count) }) } return ( <div> <h4>count: {count}</h4> <button onClick={handleClick}>點(diǎn)擊更新狀態(tài)</button> </div> ) }
顯然,在函數(shù)組件中是不能通過異步來獲取更新的值,我們可以通過 useRef來獲??;
const countRef = useRef(count) countRef.current = count const handleClick = () => { setCount(count => count + 1) console.log("value1: ", countRef.current) setTimeout(() => { console.log("value2: ", countRef.current) }) }
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
深入學(xué)習(xí)TypeScript 、React、 Redux和Ant-Design的最佳實(shí)踐
這篇文章主要介紹了深入學(xué)習(xí)TypeScript 、React、 Redux和Ant-Design的最佳實(shí)踐,TypeScript 增加了代碼的可讀性和可維護(hù)性,擁有活躍的社區(qū),,需要的朋友可以參考下2019-06-06React中使用async validator進(jìn)行表單驗(yàn)證的實(shí)例代碼
react上進(jìn)行表單驗(yàn)證是很繁瑣的,在這里使用async-validator處理起來就變的很方便了,接下來通過本文給大家介紹React中使用async validator進(jìn)行表單驗(yàn)證的方法,需要的朋友可以參考下2018-08-08React?less?實(shí)現(xiàn)縱橫柱狀圖示例詳解
這篇文章主要介紹了React?less?實(shí)現(xiàn)縱橫柱狀圖示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09淺談使用React.setState需要注意的三點(diǎn)
本篇文章主要介紹了淺談使用React.setState需要注意的三點(diǎn),提出了三點(diǎn)對(duì) React 新手來說是很容易忽略的地方,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-12-12react基于react-slick實(shí)現(xiàn)多圖輪播效果
React slick是一個(gè)使用React構(gòu)建的輪播組件,下面這篇文章主要給大家介紹了關(guān)于react基于react-slick實(shí)現(xiàn)多圖輪播效果的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-07-07基于visual studio code + react 開發(fā)環(huán)境搭建過程
今天通過本文給大家分享基于visual studio code + react 開發(fā)環(huán)境搭建過程,本文給大家介紹的非常詳細(xì),包括react安裝問題及安裝 Debugger for Chrome的方法,需要的朋友跟隨小編一起看看吧2021-07-07react中axios結(jié)合后端實(shí)現(xiàn)GET和POST請(qǐng)求方式
這篇文章主要介紹了react中axios結(jié)合后端實(shí)現(xiàn)GET和POST請(qǐng)求方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02