redux中的hooks使用詳解
useSelector
基礎(chǔ)使用
- 功能:
useSelector是 react-redux 提供的 Hook,用于從 Redux Store 中選擇(提取)狀態(tài)數(shù)據(jù) - 參數(shù)一:接收一個 選擇器函數(shù),該函數(shù)接收完整的
Redux Store 狀態(tài)(state)作為參數(shù),返回需要的數(shù)據(jù) - 參數(shù)二: 可傳入
shallowEqual,比較來決定組件是否重新渲染 - 返回值:返回 選擇器函數(shù)的結(jié)果(這里是 { count: … } 對象)
import { useSelector } from 'react-redux'
import { memo } from 'react'
const App = memo(() => {
` 使用 useSelector 將 Redux Store 中的數(shù)據(jù)映射到組件內(nèi) `
` state 參數(shù):代表整個 Redux Store 的根狀態(tài)(root state) `
const { count } = useSelector((state) => {
return {
`假設(shè)你的 Redux Store 中有一個名為 counter 的 slice(分片),該 slice 的狀態(tài)中包含 count 字段`
count: state.counter.count
}
})
return (
<div>
<h2>count: {count}</h2>
</div>
)
})
這里memo的作用:
- 用于對組件進(jìn)行淺層 props 比較,避免不必要的重新渲染。
適用場景:
- 如果 App 組件的父組件頻繁渲染,但 App 的 props 未變化,memo 可以優(yōu)化性能。
memo 與 useSelector 的關(guān)系:
- 即使 memo 包裹了組件,useSelector 仍會在 Redux Store 的 count 變化時觸發(fā)組件更新(因?yàn)閮?nèi)部狀態(tài)變化)。
第二個參數(shù) shallowEqual
- 功能:
shallowEqual是 react-redux 提供的淺比較函數(shù),用于,比較兩次選擇器返回的結(jié)果,是否 “淺層相等”。 - 適用場景:當(dāng)你的選擇器返回一個對象或數(shù)組時,shallowEqual 會逐個比較對象的每個屬性(或數(shù)組的每個元素)是否嚴(yán)格相等(===)。
- 深層嵌套無效:
shallowEqual 僅比較 第一層屬性。如果對象有深層嵌套(如 { data: { count: 1 } }),深層變化不會被檢測到。

父組件修改count時,App依賴的count發(fā)生改變,所以,父組件App會重新渲染,
但是,此時子組件也重新渲染了,子組件并沒有依賴count,而且子組件此時是用memo包裹的,memo包裹的組件只有當(dāng)其props發(fā)生改變時,才會重新渲染。
當(dāng)子組件修改msg時,App組件也重新渲染了。
這是因?yàn)槭褂昧藆seSelector,useSelector 監(jiān)聽的是 整個state數(shù)據(jù),如果state里有任何數(shù)據(jù)發(fā)生變化,當(dāng)前組件就會重新渲染。
而正常情況下,應(yīng)該是:
- 只有 msg 改變時,子組件才會渲染;
- 只有count改變時,父組件才會渲染。
useSelector的第二個參數(shù):用來比較來決定組件是否需要渲染,當(dāng)state發(fā)生改變時,useSelector 將本次映射的值與上次映射的值有沒有發(fā)生改變,有改變則重新渲染,沒有改變則不變。
// state發(fā)生變化時,父組件的useSelector判斷本次映射的count與上次映射的count是否一致,不一致則重新渲染,否則不重新渲染
const { count } = useSelector((state) => {
return {
count: state.counter.count
}
}, shallowEqual)
// state發(fā)生變化時,子組件的useSelector判斷本次映射的msg與上次映射的msg是否一致,不一致則重新渲染,否則不重新渲染
const { msg } = useSelector((state) => {
return {
msg: state.counter.msg
}
}, shallowEqual)
Reselect
Reselect 是一個專為 Redux 設(shè)計的記憶化選擇器庫,用于優(yōu)化從 Redux Store 中提取數(shù)據(jù)的性能。
它的核心思想是:通過緩存(memoization)避免重復(fù)計算,確保只有在相關(guān)狀態(tài)變化時,才重新執(zhí)行選擇器邏輯。
(1) 什么是記憶化(Memoization)?
- 定義:記憶化是一種優(yōu)化技術(shù),用于緩存函數(shù)的輸入和輸出。當(dāng)函數(shù)以相同的輸入再次調(diào)用時,直接返回緩存的結(jié)果,而不是重新計算。
- 目的:在 Redux 中,當(dāng)狀態(tài)頻繁變化但某些派生數(shù)據(jù)未變化時,避免重復(fù)計算這些派生數(shù)據(jù),從而提升性能。
(2) Reselect 的作用
場景:
- 當(dāng)你的選擇器邏輯復(fù)雜(如:組合`個狀態(tài)片段、進(jìn)行計算)時,Reselect 會自動緩存結(jié)果。
優(yōu)勢:
- 減少不必要的計算。
- 確保組件只在相關(guān)狀態(tài)變化時重新渲染。
- 保持選擇器邏輯的純凈(無副作用)。
Reselect 的核心 API:createSelector
用法:
import { createSelector } from 'reselect'
`輸入選擇器:從狀態(tài)中提取原始數(shù)據(jù)`
const selectUser = (state) => state.user 【state.user 是 Redux Store 中的一個 slice】
const selectPosts = (state) => state.posts 【state.posts 是 Redux Store 中的一個 slice】
`Reselect 的 createSelector 會按順序?qū)?輸入選擇器的返回值,作為參數(shù)傳遞給轉(zhuǎn)換函數(shù)。
因此,轉(zhuǎn)換函數(shù)中的
user 對應(yīng) selectUser的返回值(即state.user)
posts 對應(yīng) selectPosts的返回值(即state.posts)`
const selectUserData = createSelector(
[selectUser, selectPosts], `【輸入選擇器數(shù)組】`
(user, posts) => ({ `【轉(zhuǎn)換函數(shù)】`
username: user.name,
postCount: posts.length,
})
)
某組件如下:
import { useSelector } from 'react-redux'
import { selectUserData } from './selectors'
const Component = () => {
const { username, postCount } = useSelector(selectUserData)
return (
<div>
<h3>{username}</h3>
<p>Posts: {postCount}</p>
</div>
)
}
Reselect的緩存機(jī)制- 緩存觸發(fā)條件:只有當(dāng)
selectUser或selectPosts的返回值變化時,轉(zhuǎn)換函數(shù)才會重新執(zhí)行。
執(zhí)行流程:
首次調(diào)用:
- 執(zhí)行所有輸入選擇器(
selectUser和selectPosts)。 - 將結(jié)果傳遞給轉(zhuǎn)換函數(shù),計算并緩存最終值。
后續(xù)調(diào)用:
- 再次執(zhí)行輸入選擇器。
- 如果所有輸入選擇器的結(jié)果與上一次相同(嚴(yán)格相等
===),直接返回緩存值。 - 否則,重新執(zhí)行轉(zhuǎn)換函數(shù)并更新緩存。
結(jié)合shallowEqual
- 如果選擇器返回對象,可以結(jié)合
shallowEqual進(jìn)一步優(yōu)化:
const { username, postCount } = useSelector(
selectUserData,
shallowEqual
)
高級用法:組合選擇器
多層選擇器
const selectUser = (state) => state.user
const selectPosts = (state) => state.posts
const selectUserData = createSelector(
[selectUser, selectPosts],
(user, posts) => ({
username: user.name,
postCount: posts.length,
})
)
const selectUserStats = createSelector(
[selectUserData],
(userData) => ({
avgPostsPerDay: userData.postCount / 30,
})
)
帶參數(shù)的選擇器
const selectPostById = (postId) => createSelector(
[(state) => state.posts],
(posts) => posts.find(post => post.id === postId)
)
// 組件中使用
const Component = ({ postId }) => {
const post = useSelector(() => selectPostById(postId))
return <div>{post.title}</div>
}
深入解析:Reselect 的工作原理
(1) 輸入選擇器的順序
輸入選擇器的順序會影響緩存鍵的計算。例如:
const selectorA = createSelector( [selectX, selectY], (x, y) => x + y ); const selectorB = createSelector( [selectY, selectX], (y, x) => y + x );
selectorA和selectorB的緩存鍵不同(順序不同),即使邏輯相同也會重新計算。
(2) 緩存的生命周期
- 全局緩存:Reselect 的緩存是全局的,與組件實(shí)例無關(guān)。
- 狀態(tài)變化時:只要輸入選擇器的結(jié)果變化,緩存就會失效。
(3) 深層嵌套狀態(tài)的處理
- 如果狀態(tài)是深層嵌套的對象,輸入選擇器需要提取具體的字段:
const selectDeepData = createSelector( [(state) => state.deep.nested.data], (data) => data.value );
總結(jié):
Reselect 的本質(zhì):通過記憶化選擇器,避免重復(fù)計算,優(yōu)化性能。
適用場景:當(dāng)選擇器邏輯復(fù)雜、依賴多個狀態(tài)片段或需要組合數(shù)據(jù)時。
最佳實(shí)踐:
- 優(yōu)先使用
createSelector創(chuàng)建選擇器。 - 保持輸入選擇器的簡單性,將復(fù)雜邏輯放在轉(zhuǎn)換函數(shù)中。
- 結(jié)合
useSelector和shallowEqual進(jìn)一步優(yōu)化渲染性能。
useDispatch獲取dispatch函數(shù)
- 直接用
useDispatch獲取 dispatch ,派發(fā)action 即可
` 派發(fā)操作 `
const dispatch = useDispatch()
function calNumber (num) {
dispatch(addNumberAction(num))
}
return (
<div>
<h2>count:{count}</h2>
<button onClick={e => calNumber(1)}> +1 </button>
</div>
)
總結(jié)
以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
淺談React Native Flexbox布局(小結(jié))
這篇文章主要介紹了淺談React Native Flexbox布局(小結(jié)),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-01-01
react動態(tài)路由的實(shí)現(xiàn)示例
React中動態(tài)路由通過ReactRouter庫實(shí)現(xiàn),根據(jù)應(yīng)用狀態(tài)或用戶交互動態(tài)顯示或隱藏組件,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-11-11
React組件的數(shù)據(jù)掛載實(shí)現(xiàn)方式
React中state為組件內(nèi)部可變數(shù)據(jù),通過setState更新;props為外部傳入的不可變參數(shù),兩者均可觸發(fā)渲染,但state由組件維護(hù),props由父組件控制,列表需用key優(yōu)化性能,dangerouslySetInnerHTML用于內(nèi)聯(lián)HTML2025-07-07
在React中實(shí)現(xiàn)代碼熱重載(HMR)的操作步驟
在現(xiàn)代 React 開發(fā)中,代碼熱重載(HMR)是一項(xiàng)極大提升開發(fā)效率的技術(shù),它允許在不刷新整個頁面的情況下,實(shí)時更新模塊代碼,從而保留應(yīng)用狀態(tài),避免因頁面刷新導(dǎo)致的狀態(tài)丟失,本文將深入探討如何在 React 項(xiàng)目中實(shí)現(xiàn) HMR,包括其原理、配置步驟以及最佳實(shí)踐2025-05-05
深入理解React Native原生模塊與JS模塊通信的幾種方式
本篇文章主要介紹了深入理解React Native原生模塊與JS模塊通信的幾種方式,具有一定的參考價值,有興趣的可以了解一下2017-07-07
React數(shù)據(jù)傳遞之組件內(nèi)部通信的方法
這篇文章主要介紹了React數(shù)據(jù)傳遞之組件內(nèi)部通信的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-12-12
React?Hooks項(xiàng)目實(shí)戰(zhàn)
React?Hooks是React?16.8版本引入的新特性,它使得在函數(shù)組件中也能夠使用狀態(tài)(state)和其他React特性,本文就來詳細(xì)介紹一下React?Hooks項(xiàng)目實(shí)戰(zhàn),感興趣的可以了解一下2023-11-11

