網(wǎng)站首頁 編程語言 正文
usestate的常規(guī)用法
在react框架中,不適用類組件,使用函數(shù)式組件又想自定義數(shù)據(jù)維護業(yè)務(wù)開發(fā)的時候,就需要使用react提供的hook來完成。usestate就是最常見的一種hook。
const [name,setName] = useState('dx');
setName('dx1')
中括號實際是一個解構(gòu)運算,第一個name是設(shè)置的值,第二個setName是只能用來改變name的方法。
useState遇到的坑
1、useState不適合復(fù)雜對象的更改
因為useState不能像setState那樣進行合并更新,當(dāng)使用useState第二個參數(shù)進行數(shù)據(jù)更新的時候,必須傳入一個完整的結(jié)構(gòu),而不僅僅只是改變的那一部分。
如果你想讓一個復(fù)雜的對象都能實現(xiàn)響應(yīng),可以分兩種情況。
第一種情況,這個復(fù)雜的對象每次都是整體發(fā)生改變,那么也可以直接使用useState。
第二種情況,你只是想讓許多的簡單數(shù)據(jù)都放到一個對象里面,這樣便于統(tǒng)一管理,那我建議,如果這些簡單數(shù)據(jù)之間都沒什么必然聯(lián)系的話,還是分開創(chuàng)建多個state更好。
在編碼的過程中,我們寧愿以空間復(fù)雜度換取時間復(fù)雜度,多創(chuàng)建幾個變量和創(chuàng)建一個變量,在用戶體驗上并不會有太多的差別。
但如果數(shù)據(jù)過于復(fù)雜,diff算法找到對應(yīng)的變化及發(fā)生響應(yīng),大規(guī)模的重新渲染,這一過程,將會導(dǎo)致用戶體驗下降。
2、useState異步回調(diào)的問題
當(dāng)使用usestate對數(shù)據(jù)進行更新,并不能立刻獲取到最新的數(shù)據(jù)。
? const [name, setName] = useState('dx');
? const handleTest = () => {
? ? console.log(name) // dx
? ? setName('dx1')
? ? console.log(name) // dx
? }
解決的辦法。
一、配合useEffect使用
? const [name, setName] = useState('dx');
? const handleTest = () => {
? ? console.log(name) //dx
? ? setName('dx1')
? ? console.log(name)//dx
? }
??
? useEffect(() => {
? ? console.log(name) //dx1
? },[name])
二、創(chuàng)建一個新的變量保存最新的數(shù)據(jù)
? const [name, setName] = useState('dx');
? const handleTest = () => {
? ? console.log(name) //dx
? ? const newName = "dx1"
? ? setName(newName)
? ? console.log(newName) //dx1
? }
三、用一個函數(shù)包裹,不推薦使用,因為函數(shù)里面所有的東西都會全部重新定義
const [name, setName] = useState('dx');
function text () {
const handleTest = () => {
console.log(name) //dx
const newName = "dx1"
setName(newName)
console.log(name) //dx
console.log(newName) //dx1
}
useEffect(() => {
console.log(name) //dx1
},[name])
return (
<div>
{name} //點擊之前dx,點擊按鈕之后dx1
<button type="button" onClick={handleTest }>改變名字</button>
</div>
)
}
console.log(name) //點擊按鈕之前dx,點擊按鈕之后dx1
3、根據(jù)hook的規(guī)則,使用useState的位置有限制
強調(diào),所有的hook和自定義hook都遵循此規(guī)則。
僅頂層調(diào)用 Hook :不能在循環(huán),條件,嵌套函數(shù)等中調(diào)用useState()。
在多個useState()調(diào)用中,渲染之間的調(diào)用順序必須相同。
僅從React 函數(shù)調(diào)用 Hook:必須僅在函數(shù)組件或自定義鉤子內(nèi)部調(diào)用useState()。
4、使用useState,回調(diào)函數(shù)形式更改數(shù)據(jù)
const [a, setA] = useState({c:1})
/** oldA為之前的a,return為設(shè)置的新值 */
setA((oldA) => {
return {c: oldA.c + 1}
})
5、useState存入的值只是該值的引用(引用類型)
const textObj = {name:'dx'}
const [useState1, setUseState1] = useState(textObj )
const [useState2, setUseState2] = useState(textObj )
/** usestate的操作不要放在函數(shù)的最外層,這里只是簡單的代碼展示,你可以將set操作放在某個函數(shù)里面 */
setUseState1((oldUseState1) => {
oldUseState1.age = 18
return {...oldUseState1}
})
useEffect(() => {
/** 改變一個會導(dǎo)致兩個都改變,深淺拷貝的問題 */
console.log(useState1) // {name: "dx", age: 18}
console.log(useState2) // {name: "dx", age: 18}
},[
useState1
])
解決的方案
const textObj = {name:'dx'}
const [useState1, setUseState1] = useState(textObj )
const [useState2, setUseState2] = useState(JSON.parse(JSON.stringify(textObj)))
/** usestate的操作不要放在函數(shù)的最外層,這里只是簡單的代碼展示,你可以將set操作放在某個函數(shù)里面 */
setUseState1((oldUseState1) => {
oldUseState1.age = 18
return {...oldUseState1}
})
useEffect(() => {
/** 改變一個會導(dǎo)致兩個都改變,深淺拷貝的問題 */
console.log(useState1) // {name: "dx", age: 18}
console.log(useState2) // {name: "dx"}
},[
useState1
])
6、useState,如果保存引用數(shù)據(jù),useEffect檢測不到變化?
const textObj = {name:'dx'}
const [useState1, setUseState1] = useState(textObj)
/** usestate的操作不要放在函數(shù)的最外層,這里只是簡單的代碼展示,你可以將set操作放在某個函數(shù)里面 */
setUseState1((oldUseState1) => {
oldUseState1.age = 18
return oldUseState1
useEffect(() => {
console.log(useState1)
},[
useState1
])
//結(jié)果是沒有任何反應(yīng)
解決方法
const textObj = {name:'dx'}
const [useState1, setUseState1] = useState(textObj)
/** usestate的操作不要放在函數(shù)的最外層,這里只是簡單的代碼展示,你可以將set操作放在某個函數(shù)里面 */
setUseState1((oldUseState1) => {
oldUseState1.age = 18
/** 返回一個新的對象,useEffectc才能檢測得到 */
return {...oldUseState1}
useEffect(() => {
console.log(useState1) // {name: "dx", age: 18}
},[
useState1
])
7、useState無法保存一個函數(shù)
你是否嘗試著將函數(shù)的引用作為一個變量保存到useState中去呢?
比如:
const testFunciton1 = () => {
console.log({name: 'dx',age: '18'})
}
/** usestate保存函數(shù)測試 */
const [stateFunction, setstateFunction] = useState<() => void>(testFunciton1);
useEffect(() => {
console.log(stateFunction)
}, [stateFunction])
打印結(jié)果
代碼中從未調(diào)用過testFunciton1 ,結(jié)果testFunciton1卻被執(zhí)行了
useEffect打印出來的卻是一個undefined。
稍微改動一下代碼,再測試
const testFunciton1 = () => {
console.log({name: 'dx',age: '18'})
return {
name: 'yx',
age: '17'
}
}
/** usestate保存函數(shù)測試 */
const [stateFunction, setstateFunction] = useState<() => void>(testFunciton1);
useEffect(() => {
console.log(stateFunction)
}, [stateFunction])
結(jié)果
很明顯,在useState中,函數(shù)會自動調(diào)用,并且保存函數(shù)返回的值,而不能保存函數(shù)本身。
解決的方案
使用useState不能保存函數(shù),那么可以使用useCallback這個hook。
/** useCallback,使用參數(shù)與useEffect一致 */
const testFunction = useCallback(() => {
// useCallback返回的函數(shù)在useCallbak中構(gòu)建
const testFunciton1 = () => {
console.log({ name: 'dx', age: '18' });
return {
name: 'yx',
age: '17',
};
};
return testFunciton1;
}, []);
useEffect(() => {
console.log(testFunction());
}, [testFunction]);
結(jié)果
useState實現(xiàn)原理
前一段時間面試某大廠的時候,講到了useState這個hook,要求簡單寫一下useState的實現(xiàn)原理,以下代碼只是一個粗淺的原理。
function useState(init) {
let state;
// useState無法保存函數(shù)
if(typeof init === 'function') {
state = init()
} else {
state = init
}
const setState = (change) => {
// 判斷一下是否傳遞過來的是函數(shù)
if(typeof change === 'function') {
// 如果是函數(shù),調(diào)用,并將之前的state傳過去,接收到的返回值作為新的state并賦值
state = change(state)
} else {
// 如果不是函數(shù),直接賦值
state = change;
}
}
return [state, setState]
}
原文鏈接:https://blog.csdn.net/glorydx/article/details/105676697
相關(guān)推薦
- 2022-07-01 python神經(jīng)網(wǎng)絡(luò)Densenet模型復(fù)現(xiàn)詳解_python
- 2022-12-05 Go?reflect?反射原理示例詳解_Golang
- 2022-05-23 ES6新增關(guān)鍵字let和const介紹_基礎(chǔ)知識
- 2022-11-28 ContentProvider客戶端處理provider邏輯分析_Android
- 2022-03-05 C語言宏函數(shù)container?of()簡介_C 語言
- 2023-02-14 使用PowerShell獲取Trustedinstaller權(quán)限的問題_PowerShell
- 2022-09-24 教你創(chuàng)建一個帶診斷工具的.NET鏡像_C#教程
- 2022-05-24 C++實現(xiàn)路口交通燈模擬系統(tǒng)_C 語言
- 最近更新
-
- 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之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- 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同步修改后的遠程分支