React Redux應(yīng)用示例詳解
一 React-Redux的應(yīng)用
1.學(xué)習(xí)文檔
- 英文文檔: https://redux.js.org/
- 中文文檔: https://cn.redux.js.org/
- Github: https://github.com/reactjs/redux
2.Redux的需求
- 狀態(tài)的集中管理
- 任意頁(yè)面與組件之間的數(shù)據(jù)傳遞
- 狀態(tài)管理的可預(yù)測(cè)
- 數(shù)據(jù)的本地化緩存提升性能
說(shuō)明:
隨著對(duì)JavaScript單頁(yè)應(yīng)用程序的要求變得越來(lái)越復(fù)雜,我們的代碼必須比以前更多地處理狀態(tài)。此狀態(tài)可以包括服務(wù)器響應(yīng)和緩存數(shù)據(jù),以及本地創(chuàng)建的尚未保存到服務(wù)器的數(shù)據(jù)。 UI狀態(tài)的復(fù)雜性也在增加,因?yàn)槲覀冃枰芾砘顒?dòng)路線,選定標(biāo)簽,旋鈕,分頁(yè)控件等。 管理這個(gè)不斷變化的狀態(tài)是困難的。
如果一個(gè)模型可以更新另一個(gè)模型,那么一個(gè)視圖可以更新一個(gè)模型,該模型會(huì)更新另一個(gè)模型,而這又可能導(dǎo)致另一個(gè)視圖更新。在某種程度上,您不再理解您的應(yīng)用程序會(huì)發(fā)生什么情況,因?yàn)槟呀?jīng)失去了對(duì)其狀態(tài)的何時(shí),為何和如何的控制。
當(dāng)系統(tǒng)不透明且不確定時(shí),很難重現(xiàn)錯(cuò)誤或添加新功能。 好像這還不夠糟糕,請(qǐng)考慮新的要求在前端產(chǎn)品開發(fā)中變得常見(jiàn)。作為開發(fā)人員,我們需要處理樂(lè)觀的更新,服務(wù)器端渲染,在執(zhí)行路由轉(zhuǎn)換之前獲取數(shù)據(jù)等等。
我們發(fā)現(xiàn)自己試圖去處理一個(gè)我們以前從來(lái)沒(méi)有處理過(guò)的復(fù)雜問(wèn)題,而且我們不可避免地提出這個(gè)問(wèn)題:是放棄的時(shí)候了嗎?答案是不。
這種復(fù)雜性很難處理,因?yàn)槲覀冋诨旌蟽蓚€(gè)對(duì)人類頭腦非常難以推理的概念:突變和異步性。我把它們叫做曼托斯和可樂(lè)。兩者在分離方面都很出色,但它們一起造成一團(tuán)糟。像React這樣的庫(kù)試圖通過(guò)去除異步和直接DOM操作來(lái)解決視圖層中的這個(gè)問(wèn)題。但是,管理數(shù)據(jù)的狀態(tài)由您決定。這是Redux進(jìn)入的地方。
3.什么是Redux
- redux是一個(gè)獨(dú)立專門用于做狀態(tài)管理的JS庫(kù)(不是react插件庫(kù))
- 它可以用在react、angular、vue等項(xiàng)目中,但基本與react配合使用
- 作用:集中式管理react應(yīng)用中多個(gè)組件共享的狀態(tài)
4.什么情況下需要使用redux
- 總體原則: 大型項(xiàng)目狀態(tài)管理復(fù)雜才用
- 某個(gè)組件的狀態(tài),需要共享
- 某個(gè)狀態(tài)需要在任何地方都可以拿到
- 一個(gè)組件需要改變?nèi)譅顟B(tài)
- 一個(gè)組件需要改變另一個(gè)組件的狀態(tài)
二、最新React-Redux 的流程
安裝Redux Toolkit
# NPM
npm install @reduxjs/toolkit
# Yarn
yarn add @reduxjs/toolkit
創(chuàng)建一個(gè) React Redux 應(yīng)用
官方推薦的使用 React 和 Redux 創(chuàng)建新應(yīng)用的方式是使用官方 Redux+JS 模版或Redux+TS 模板,它基于Create React App,利用了Redux Toolkit和 Redux 與 React 組件的集成.
# Redux + Plain JS template
npx create-react-app my-app --template redux
# Redux + TypeScript template
npx create-react-app my-app --template redux-typescript
Redux 核心庫(kù)?
Redux 核心庫(kù)同樣有 NPM 軟件包,可與模塊捆綁器或 Node 應(yīng)用程序一起使用,安裝方式如下:
# NPM
npm install redux
# Yarn
yarn add redux
基礎(chǔ)示例
應(yīng)用的整體全局狀態(tài)以對(duì)象樹的方式存放于單個(gè)store。 唯一改變狀態(tài)樹(state tree)的方法是創(chuàng)建action,一個(gè)描述發(fā)生了什么的對(duì)象,并將其dispatch給 store。 要指定狀態(tài)樹如何響應(yīng) action 來(lái)進(jìn)行更新,你可以編寫純r(jià)educer函數(shù),這些函數(shù)根據(jù)舊 state 和 action 來(lái)計(jì)算新 state。
import { createStore } from 'redux'
/**
* 這是一個(gè) reducer 函數(shù):接受當(dāng)前 state 值和描述“發(fā)生了什么”的 action 對(duì)象,它返回一個(gè)新的 state 值。
* reducer 函數(shù)簽名是 : (state, action) => newState
*
* Redux state 應(yīng)該只包含普通的 JS 對(duì)象、數(shù)組和原語(yǔ)。
* 根狀態(tài)值通常是一個(gè)對(duì)象。 重要的是,不應(yīng)該改變 state 對(duì)象,而是在 state 發(fā)生變化時(shí)返回一個(gè)新對(duì)象。
*
* 你可以在 reducer 中使用任何條件邏輯。 在這個(gè)例子中,我們使用了 switch 語(yǔ)句,但這不是必需的。
*
*/
function counterReducer(state = { value: 0 }, action) {
switch (action.type) {
case 'counter/incremented':
return { value: state.value + 1 }
case 'counter/decremented':
return { value: state.value - 1 }
default:
return state
}
}
// 創(chuàng)建一個(gè)包含應(yīng)用程序 state 的 Redux store。
// 它的 API 有 { subscribe, dispatch, getState }.
let store = createStore(counterReducer)
// 你可以使用 subscribe() 來(lái)更新 UI 以響應(yīng) state 的更改。
// 通常你會(huì)使用視圖綁定庫(kù)(例如 React Redux)而不是直接使用 subscribe()。
// 可能還有其他用例對(duì) subscribe 也有幫助。
store.subscribe(() => console.log(store.getState()))
// 改變內(nèi)部狀態(tài)的唯一方法是 dispatch 一個(gè) action。
// 這些 action 可以被序列化、記錄或存儲(chǔ),然后再重放。
store.dispatch({ type: 'counter/incremented' })
// {value: 1}
store.dispatch({ type: 'counter/incremented' })
// {value: 2}
store.dispatch({ type: 'counter/decremented' })
// {value: 1}Redux Toolkit 示例
import { createSlice, configureStore } from '@reduxjs/toolkit'
const counterSlice = createSlice({
name: 'counter',
initialState: {
value: 0
},
reducers: {
incremented: state => {
// Redux Toolkit 允許在 reducers 中編寫 "mutating" 邏輯。
// 它實(shí)際上并沒(méi)有改變 state,因?yàn)槭褂玫氖?Immer 庫(kù),檢測(cè)到“草稿 state”的變化并產(chǎn)生一個(gè)全新的
// 基于這些更改的不可變的 state。
state.value += 1
},
decremented: state => {
state.value -= 1
}
}
})
export const { incremented, decremented } = counterSlice.actions
const store = configureStore({
reducer: counterSlice.reducer
})
// 可以訂閱 store
store.subscribe(() => console.log(store.getState()))
// 將我們所創(chuàng)建的 action 對(duì)象傳遞給 `dispatch`
store.dispatch(incremented())
// {value: 1}
store.dispatch(incremented())
// {value: 2}
store.dispatch(decremented())
// {value: 1}三、使用教程
安裝Redux Toolkit和React-Redux?
添加 Redux Toolkit 和 React-Redux 依賴包到你的項(xiàng)目中:
創(chuàng)建 Redux Store?
創(chuàng)建src/app/store.js文件。從 Redux Toolkit 引入configureStoreAPI。我們從創(chuàng)建一個(gè)空的 Redux store 開始,并且導(dǎo)出它:
app/store.js
import { configureStore } from '@reduxjs/toolkit'
export default configureStore({
reducer: {}
})npm install @reduxjs/toolkit react-redux
上面代碼創(chuàng)建了 Redux store ,并且自動(dòng)配置了 Redux DevTools 擴(kuò)展 ,這樣你就可以在開發(fā)時(shí)調(diào)試 store。
為React提供Redux Store?
創(chuàng)建 store 后,便可以在 React 組件中使用它。 在 src/index.js 中引入我們剛剛創(chuàng)建的 store , 通過(guò) React-Redux 的<Provider>將<App>包裹起來(lái),并將 store 作為 prop 傳入。
index.js
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
import store from './app/store'
import { Provider } from 'react-redux'
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)創(chuàng)建Redux State Slice?
創(chuàng)建src/features/counter/counterSlice.js文件。在該文件中從 Redux Toolkit 引入createSliceAPI。
創(chuàng)建 slice 需要一個(gè)字符串名稱來(lái)標(biāo)識(shí)切片、一個(gè)初始 state 以及一個(gè)或多個(gè)定義了該如何更新 state 的 reducer 函數(shù)。slice 創(chuàng)建后 ,我們可以導(dǎo)出 slice 中生成的 Redux action creators 和 reducer 函數(shù)。
Redux 要求我們通過(guò)創(chuàng)建數(shù)據(jù)副本和更新數(shù)據(jù)副本,來(lái)實(shí)現(xiàn)不可變地寫入所有狀態(tài)更新。不過(guò) Redux ToolkitcreateSlice和createReducer在內(nèi)部使用 Immer 允許我們編寫“可變”的更新邏輯,變成正確的不可變更新。
features/counter/counterSlice.js
import { createSlice } from '@reduxjs/toolkit'
export const counterSlice = createSlice({
name: 'counter',
initialState: {
value: 0
},
reducers: {
increment: state => {
// Redux Toolkit 允許我們?cè)?reducers 寫 "可變" 邏輯。它
// 并不是真正的改變狀態(tài)值,因?yàn)樗褂昧?Immer 庫(kù)
// 可以檢測(cè)到“草稿狀態(tài)“ 的變化并且基于這些變化生產(chǎn)全新的
// 不可變的狀態(tài)
state.value += 1
},
decrement: state => {
state.value -= 1
},
incrementByAmount: (state, action) => {
state.value += action.payload
}
}
})
// 每個(gè) case reducer 函數(shù)會(huì)生成對(duì)應(yīng)的 Action creators
export const { increment, decrement, incrementByAmount } = counterSlice.actions
export default counterSlice.reducer將Slice Reducers添加到Store 中?
下一步,我們需要從計(jì)數(shù)切片中引入 reducer 函數(shù),并將它添加到我們的 store 中。通過(guò)在 reducer 參數(shù)中定義一個(gè)字段,我們告訴 store 使用這個(gè) slice reducer 函數(shù)來(lái)處理對(duì)該狀態(tài)的所有更新。
app/store.js
import { configureStore } from '@reduxjs/toolkit'
import counterReducer from '../features/counter/counterSlice'
export default configureStore({
reducer: {
counter: counterReducer
}
})在React組件中使用Redux狀態(tài)和操作?
現(xiàn)在我們可以使用 React-Redux 鉤子讓 React 組件與 Redux store 交互。我們可以使用useSelector從 store 中讀取數(shù)據(jù),使用useDispatchdispatch actions。創(chuàng)建包含<Counter>組件的src/features/counter/Counter.js文件,然后將該組件導(dǎo)入App.js并在<App>中渲染它。
features/counter/Counter.js
import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { decrement, increment } from './counterSlice'
import styles from './Counter.module.css'
export function Counter() {
const count = useSelector(state => state.counter.value)
const dispatch = useDispatch()
return (
<div>
<div>
<button
aria-label="Increment value"
onClick={() => dispatch(increment())}
>
Increment
</button>
<span>{count}</span>
<button
aria-label="Decrement value"
onClick={() => dispatch(decrement())}
>
Decrement
</button>
</div>
</div>
)
}現(xiàn)在,每當(dāng)你點(diǎn)擊”遞增“和“遞減”按鈕。
- 會(huì) dispatch 對(duì)應(yīng)的 Redux action 到 store
- 在計(jì)數(shù)器切片對(duì)應(yīng)的 reducer 中將看到 action 并更新其狀態(tài)
<Counter>組件將從 store 中看到新的狀態(tài),并使用新數(shù)據(jù)重新渲染組件
你學(xué)到了什么?
這是關(guān)于如何通過(guò) React 設(shè)置和使用 Redux Toolkit 的簡(jiǎn)要概述。 回顧細(xì)節(jié):
總結(jié)
使用configureStore創(chuàng)建 Redux store
configureStore接受reducer函數(shù)作為命名參數(shù)configureStore使用的好用的默認(rèn)設(shè)置自動(dòng)設(shè)置 store
為 React 應(yīng)用程序組件提供 Redux store
- 使用 React-Redux
<Provider>組件包裹你的<App /> - 傳遞 Redux store 如
<Provider store={store}>
使用createSlice創(chuàng)建 Redux "slice" reducer
- 使用字符串名稱、初始狀態(tài)和命名的 reducer 函數(shù)調(diào)用“createSlice”
- Reducer 函數(shù)可以使用 Immer 來(lái)“改變”狀態(tài)
- 導(dǎo)出生成的 slice reducer 和 action creators
在 React 組件中使用 React-ReduxuseSelector/useDispatch鉤子
- 使用
useSelector鉤子從 store 中讀取數(shù)據(jù) - 使用
useDispatch鉤子獲取dispatch函數(shù),并根據(jù)需要 dispatch actions
到此這篇關(guān)于React Redux應(yīng)用示例詳解的文章就介紹到這了,更多相關(guān)React Redux內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
React中useState的使用方法及注意事項(xiàng)
useState通過(guò)在函數(shù)組件里調(diào)用它來(lái)給組件添加一些內(nèi)部state,下面這篇文章主要給大家介紹了關(guān)于React中useState的使用方法及注意事項(xiàng)的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-08-08
react+react-beautiful-dnd實(shí)現(xiàn)代辦事項(xiàng)思路詳解
這篇文章主要介紹了react+react-beautiful-dnd實(shí)現(xiàn)代辦事項(xiàng),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06
React18使用Echarts和MUI實(shí)現(xiàn)一個(gè)交互性的溫度計(jì)
這篇文章我們將結(jié)合使用React 18、Echarts和MUI(Material-UI)庫(kù),展示如何實(shí)現(xiàn)一個(gè)交互性的溫度計(jì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-01-01
React Native 混合開發(fā)多入口加載方式詳解
這篇文章主要介紹了React Native 混合開發(fā)多入口加載方式詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
React 性能優(yōu)化之非必要的渲染問(wèn)題解決
本文主要介紹了React 性能優(yōu)化之非必要的渲染問(wèn)題解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07
React實(shí)現(xiàn)浮層組件的思路與方法詳解
React?浮層組件(也稱為彈出組件或彈窗組件)通常是指在用戶界面上浮動(dòng)顯示的組件,本文主要介紹了浮層組件的實(shí)現(xiàn)方法,感興趣的小伙伴可以了解下2024-02-02
React Ant Design樹形表格的復(fù)雜增刪改操作
這篇文章主要介紹了React Ant Design樹形表格的復(fù)雜增刪改操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-11-11

