react使用useState修改對(duì)象或者數(shù)組的值無(wú)法改變視圖的問(wèn)題
使用useState修改對(duì)象或者數(shù)組的值無(wú)法改變視圖
在react中使用useState無(wú)法改變視圖,數(shù)據(jù)改變但是視圖未改變
未渲染的代碼如下:
const [needLists,setNeedLists]=useState([])
const pressDownEnter=(e)=>{
? ? if(e.keyCode===13){
? ? ? needLists.push({
? ? ? ? content:e.target.value,
? ? ? ? status:0
? ? ? })
? ? ? setNeedLists(needLists)
? ? ? e.target.value=""
? ? }
? }未發(fā)生改變的原因可能是因?yàn)閚eedLists本身并沒(méi)有變化,因?yàn)閚eedLists變量存儲(chǔ)的地址是不變的
解決辦法
通過(guò)數(shù)據(jù)結(jié)構(gòu)讓傳入的新值和原來(lái)的數(shù)組指向的不是同一片內(nèi)存,就能觸發(fā)dom的更新
const [needLists,setNeedLists]=useState([])
const pressDownEnter=(e)=>{
? ? if(e.keyCode===13){
? ? ? needLists.push({
? ? ? ? content:e.target.value,
? ? ? ? status:0
? ? ? })
? ? ? setNeedLists([...needLists])
? ? ? e.target.value=""
? ? }
? }對(duì)于對(duì)象的修改也是同理可以通過(guò){…obj}
關(guān)于useState使用及注意事項(xiàng)
一、基本使用
useState是 react 提供的一個(gè)定義響應(yīng)式變量的 hook 函數(shù),基本語(yǔ)法如下:
const [count, setCount] = useState(initialCount)
它返回一個(gè)狀態(tài)和一個(gè)修改狀態(tài)的方法,狀態(tài)需要通過(guò)這個(gè)方法來(lái)進(jìn)行修改;initialCount 是我們傳入的一個(gè)初始狀態(tài),它是惰性的,我們可以通過(guò)傳一個(gè)函數(shù)來(lái)返回一個(gè)值當(dāng)作初始狀態(tài),并且這個(gè)函數(shù)只會(huì)在初始渲染時(shí)執(zhí)行一次;
const [count, setCount] = useState(() => {
const initialCount = someExpensiveComputation();
return initialCount
})
接下來(lái)把定義好的狀態(tài)運(yùn)用到頁(yè)面:
import { useState } from 'react'
function App() {
const [count, setCount] = useState(0)
const handleClick = () => {
setCount(count + 1)
// 傳入一個(gè)函數(shù),更新的值是基于之前的值來(lái)執(zhí)行
// setCount(count => count + 1)
}
return (
<div>
<h4>count: {count}</h4>
<button onClick={ handleClick }>點(diǎn)擊更新?tīng)顟B(tài)</button>
</div>
)
}
頁(yè)面渲染完成后,我們可以看到 count的值是 0,當(dāng)我們點(diǎn)擊按鈕時(shí),會(huì)將 count的值加 1,頁(yè)面也同時(shí)更新;

了解完基礎(chǔ)用法后,我們可以思考幾個(gè)問(wèn)題;
- setCount修改值時(shí)它是同步還是異步?
- 連續(xù)調(diào)用 setCount會(huì)發(fā)生什么?
第一個(gè)問(wèn)題:setCount修改值時(shí)它是同步還是異步?
const handleClick = () => {
console.log("value1: ", count)
setCount(count => count + 1)
console.log("value2: ", count)
}

從圖中我們可以看出,頁(yè)面的值是更新了,但是控制臺(tái)打印的是之前的值,這是不是也表示 setCount是異步的呢?我們換一種方法,用異步來(lái)修改狀態(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īng)顟B(tài)</button>
</div>
)
}

從圖中我們可以看出,我們已經(jīng)拿到了更新之后的值,useRef不僅可以用于訪問(wèn) DOM 節(jié)點(diǎn),也可以用來(lái)表示一個(gè)容器,current屬性可以保存任何值,而且useRef返回的對(duì)象會(huì)在整個(gè)生命周期內(nèi)保持;
第二個(gè)問(wèn)題:連續(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)樗碌闹凳腔谥暗闹祦?lái)執(zhí)行,所以在開(kāi)發(fā)中推薦使用函數(shù)傳入的形式進(jìn)行修改;
二、注意事項(xiàng)
1、復(fù)雜變量的修改
對(duì)于復(fù)雜類型的變量我們修改時(shí)需要重新定義,在原來(lái)數(shù)據(jù)的基礎(chǔ)上修改不會(huì)引起組件的重新渲染,因?yàn)?React 組件的更新機(jī)制只進(jìn)行淺對(duì)比,也就是更新某個(gè)復(fù)雜類型數(shù)據(jù)時(shí)只要它的引用地址沒(méi)變,就不會(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ù)組來(lái)修改,在原數(shù)組上的修改不會(huì)引起組件的重新渲染,React 組件的更新機(jī)制對(duì)只進(jìn)行淺對(duì)比,也就是更新某個(gè)復(fù)雜類型數(shù)據(jù)時(shí)只要它的引用地址沒(méi)變,就不會(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īng)顟B(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īng)顟B(tài)</button>
</div>
)
}

顯然,在函數(shù)組件中是不能通過(guò)異步來(lái)獲取更新的值,我們可以通過(guò) useRef來(lái)獲??;
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)文章
React函數(shù)式組件Hook中的useEffect函數(shù)的詳細(xì)解析
useEffect是react v16.8新引入的特性。我們可以把useEffect hook看作是componentDidMount、componentDidUpdate、componentWillUnmounrt三個(gè)函數(shù)的組合2022-10-10
React中Portals與錯(cuò)誤邊界處理實(shí)現(xiàn)
本文主要介紹了React中Portals與錯(cuò)誤邊界處理實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-07-07
React?Hooks中?useRef和useImperativeHandle的使用方式
這篇文章主要介紹了React?Hooks中?useRef和useImperativeHandle的使用方式,文中說(shuō)明了useRef和useCallback一起使用,?可以解決閉包陷阱的問(wèn)題,本文結(jié)合實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-10-10
webpack4+react多頁(yè)面架構(gòu)的實(shí)現(xiàn)
webpack在單頁(yè)面打包上應(yīng)用廣泛,以create-react-app為首的腳手架眾多。這篇文章主要介紹了webpack4+react多頁(yè)面架構(gòu)的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-10-10
React.js中常用的ES6寫(xiě)法總結(jié)(推薦)
本篇文章中主要介紹了React.js中常用的ES6寫(xiě)法總結(jié)(推薦),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-05-05

