網(wǎng)站首頁 編程語言 正文
react useState異步,數(shù)據(jù)不能獲取到
useState() 屬于異步函數(shù),在useState() 第一次存儲的時候,值會存儲不上
因為react中state的更新是異步的,我們setState后,react不會立刻對值進行改變,而是將其暫時放入pedding隊列中。react會合并多個state,然后值render一次,所以不要在循環(huán)中使用useState,它有可能只render最后一次set值,但是當(dāng)傳入一個函數(shù)時,函數(shù)就會被放入一個隊列中,然后按照順序執(zhí)行。
問題
const Dva = () => {
const [arr, setArr] = useState([0])
// 兩個回調(diào)函數(shù),第一個回調(diào)函數(shù)完成后,會將返回結(jié)果作為參數(shù),傳入第二個參數(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的使用及注意事項
基本使用
useState是 react 提供的一個定義響應(yīng)式變量的 hook 函數(shù),基本語法如下:
const [count, setCount] = useState(initialCount)
- 它返回一個狀態(tài)和一個修改狀態(tài)的方法,狀態(tài)需要通過這個方法來進行修改;
- initialCount 是我們傳入的一個初始狀態(tài),它是惰性的,我們可以通過傳一個函數(shù)來返回一個值當(dāng)作初始狀態(tài),并且這個函數(shù)只會在初始渲染時執(zhí)行一次;
const [count, setCount] = useState(() => {
const initialCount = someExpensiveComputation();
return initialCount
})
接下來把定義好的狀態(tài)運用到頁面:
import { useState } from 'react'
function App() {
const [count, setCount] = useState(0)
const handleClick = () => {
setCount(count + 1)
// 傳入一個函數(shù),更新的值是基于之前的值來執(zhí)行
// setCount(count => count + 1)
}
return (
<div>
<h4>count: {count}</h4>
<button onClick={ handleClick }>點擊更新狀態(tài)</button>
</div>
)
}
頁面渲染完成后,我們可以看到 count的值是 0,當(dāng)我們點擊按鈕時,會將 count的值加 1,頁面也同時更新;
了解完基礎(chǔ)用法后,我們可以思考幾個問題;
- setCount修改值時它是同步還是異步?
- 連續(xù)調(diào)用 setCount會發(fā)生什么?
第一個問題:setCount修改值時它是同步還是異步?
const handleClick = () => {
console.log("value1: ", count)
setCount(count => count + 1)
console.log("value2: ", count)
}
從圖中我們可以看出,頁面的值是更新了,但是控制臺打印的是之前的值,這是不是也表示 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 是異步更新的;那我們要怎么拿到更新后的值呢,我們可以用另外一個 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}>點擊更新狀態(tài)</button>
</div>
)
}
從圖中我們可以看出,我們已經(jīng)拿到了更新之后的值,useRef不僅可以用于訪問 DOM 節(jié)點,也可以用來表示一個容器,current屬性可以保存任何值,而且useRef返回的對象會在整個生命周期內(nèi)保持;
第二個問題:連續(xù)調(diào)用 setCount會發(fā)生什么?
(1)傳入一個基于狀態(tài)的值
const handleClick = () => {
console.log("value1: ", count)
setCount(count + 1)
console.log("value2: ", count)
setCount(count + 1)
console.log("value3: ", count)
}
從圖片可以看出,如果我們傳入的是一個普通值,他只會進行最后一次更新;
(2)傳入一個函數(shù)
const handleClick = () => {
console.log("value1: ", count)
setCount(count => count + 1)
console.log("value2: ", count)
setCount(count => count + 1)
console.log("value3: ", count)
}
可以看出,傳入一個函數(shù)的話,它會進行兩次賦值,因為它更新的值是基于之前的值來執(zhí)行,所以在開發(fā)中推薦使用函數(shù)傳入的形式進行修改;
注意事項
1、復(fù)雜變量的修改
對于復(fù)雜類型的變量我們修改時需要重新定義,在原來數(shù)據(jù)的基礎(chǔ)上修改不會引起組件的重新渲染,因為 React 組件的更新機制只進行淺對比,也就是更新某個復(fù)雜類型數(shù)據(jù)時只要它的引用地址沒變,就不會重新渲染組件;舉個例子
function App() {
const [arr, setArr] = useState([1])
const pushData = () => {
arr.push(4)
setArr(arr)
}
return (
<div>
<h4>{arr.join("-")}</h4>
<button onClick={pushData}>點擊添加數(shù)組</button>
</div>
)
}
上面的代碼在點擊按鈕時,視圖不會發(fā)生變化,但是 arr的值是變化了,如果想修改這個數(shù)組,需要重新定義一個數(shù)組來修改,在原數(shù)組上的修改不會引起組件的重新渲染,React 組件的更新機制對只進行淺對比,也就是更新某個復(fù)雜類型數(shù)據(jù)時只要它的引用地址沒變,就不會重新渲染組件;
const pushData = () => {
setArr([...arr, 4])
}
2、異步操作獲取更新的值
在類組件里面,修改值時異步操作可以拿到更新后的值,但是在函數(shù)組件,異步獲取是拿不到更新后的值的,舉個例子對比一下:
類組件
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}>點擊更新狀態(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}>點擊更新狀態(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)
})
}
原文鏈接:https://blog.csdn.net/momo66_/article/details/121835641
相關(guān)推薦
- 2021-11-27 nginx中的兩個模塊的proxy_pass的區(qū)別解析_nginx
- 2022-09-16 Go+Kafka實現(xiàn)延遲消息的實現(xiàn)示例_Golang
- 2022-05-29 Python格式化字符串的案例方法_python
- 2022-04-17 將本地jar放到pom中被maven管理
- 2023-01-30 React合成事件及Test?Utilities在Facebook內(nèi)部進行測試_React
- 2022-04-01 CentOS安裝Docker的方法_docker
- 2022-07-26 FastDFS-支持雙IP、IPV6
- 2022-12-22 OpenHarmony如何調(diào)用電話服務(wù)API撥打電話_Android
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支