Redux
- Redux
- Redux 概念
- 1、實現計數器
- 2、Redux 資料流架構
- Redux 與 React — 環境準備
- 1、配套工具
- 2、配置基礎環境
- 3、store 目錄結構設計
- Redux 與 React — 實現 counter
- 1、整體路徑熟悉
- 2、使用 React Toolkit 建立 counterStore
- 3、為 React 注入 store
- 4、React 元件使用 store 中的資料
- 5、React 元件修改 store 中的資料
- Redux 與 React — 提交 action 傳參
- Redux 與 React — 非同步 action 處理
- Redux 除錯 — devtools
Redux 概念
Redux 是 React 最常用的集中狀態管理工具,類似於 Vue 中的 Pinia(Vuex),可以獨立於框架執行。
作用:透過集中管理的方式管理應用的狀態。
.
為什麼要使用 Redux ?
- 獨立於元件,無視元件之間的層級關係,簡化通訊問題;
- 單項資料流清晰,易於定位 bug;
- 除錯工具配套良好,方便除錯。
1、實現計數器
需求:不和任何框架繫結,不使用任何構建工具,使用純 Redux 實現計數器。
.
使用步驟:
- 定義一個
reducer
函式 (根據當前想要做的修改返回一個新的狀態) - 使用
createStore
方法傳入reducer
函式 生成一個store 例項物件
- 使用 store 例項的
subscribe
方法 訂閱資料的變化(資料一旦變化,可以得到通知) - 使用 store 例項的
dispatch 方法提交 action 物件
觸發資料變化(告訴 reducer 你想怎麼改資料) - 使用 store 例項的
getState
方法 獲取最新的狀態資料更新到檢視中
程式碼實現:
<button id="decrement">-</button>
<span id="count">0</span>
<button id="increment">+</button>
<script src="https://unpkg.com/redux@latest/dist/redux.min.js"></script>
<script>
// 1、定義 reducer 函式
// 內部主要的工作是根據不同的 action 物件返回不同的新的 state
// state:管理的資料初始狀態
// action:物件 type 標記當前
function counterReducer (state = { count: 0 }, action) {
switch (action.type) {
case 'INCREMENT':
return { count: state.count + 1 }
case 'DECREMENT':
return { count: state.count - 1 }
default:
return state
}
}
// 使用reducer函式生成store例項
const store = Redux.createStore(counterReducer)
// 訂閱資料變化
store.subscribe(() => {
console.log(store.getState())
document.getElementById('count').innerText = store.getState().count
})
// 增
const inBtn = document.getElementById('increment')
inBtn.addEventListener('click', () => {
store.dispatch({
type: 'INCREMENT'
})
})
// 減
const dBtn = document.getElementById('decrement')
dBtn.addEventListener('click', () => {
store.dispatch({
type: 'DECREMENT'
})
})
</script>
2、Redux 資料流架構
Redux 的難點是理解它對於資料修改的規則,下圖動態展示了在整個資料的修改中,資料的流向:
.
為了職責清晰,資料流嚮明確,Redux 把整個資料修改的流程分成了三個核心概念,分別是:state
、action
和 reducer
:
state
:一個物件,存放著我們管理的資料action
:一個物件,用來描述你想怎麼改資料reducer
:一個函式,根據 action 的描述生成一個新的 state
Redux 與 React — 環境準備
Redux 雖然是一個框架無關可以獨立執行的外掛,但是社群通常還是把它與 React 繫結在一起使用,以一個計數器案例體驗一下 Redux + React 的基礎使用
1、配套工具
在 React 中使用
redux
,官方要求安裝 2 個其他外掛 —Redux Toolkit
和react-redux
。
Redux Toolkit
(RTK)— 官方推薦編寫 Redux 邏輯的方式,是一套工具的集合集,簡化書寫方式。
.
react-redux
— 用來連結 Redux 和 React 元件的中介軟體。
.
2、配置基礎環境
npm i @reduxjs/toolkit react-redux
3、store 目錄結構設計
.
-
通常集中狀態管理的部分都會單獨建立一個單獨的
store
目錄 -
應用通常會有很多個子 store 模組,所以建立一個
modules
目錄,在內部編寫業務分類的子 store -
store 中的入口檔案 index.js 的作用是組合 modules 中所有的子模組,並匯出 store
Redux 與 React — 實現 counter
1、整體路徑熟悉
.
2、使用 React Toolkit 建立 counterStore
.
counterStore.js
import {createSlice} from "@reduxjs/toolkit"
const counterStore = createSlice({
name: "counter",
// 初始狀態資料
initialState: {
count: 0,
},
// 修改資料的同步方法
reducers: {
fn(state) {
state.count += 1
},
},
})
// 解構出建立 action 物件的函式(actionCreator)
const {fn} = counterStore.actions
// 獲取 reducer 函式
const counterReducer = counterStore.reducer
// 匯出建立 action 物件的函式和 reducer 函式
export {fn}
export default counterReducer
store/index.js
import {configureStore} from "@reduxjs/toolkit"
import counterReducer from "./modules/counterStore.js"
// 建立根 store 組合子模組
const store = configureStore({
reducer: {
counter: counterReducer,
},
})
export default store
3、為 React 注入 store
react-redux
負責把 Redux 和 React 連結起來,內建 Provider 元件 透過 store 引數把建立好的 store 例項注入到應用中,連結正式建立。
.
import React from "react"
import ReactDOM from "react-dom/client"
import App from "./App.jsx"
import {Provider} from "react-redux"
import store from "./store/index.js"
ReactDOM.createRoot(document.getElementById("root")).render(
<React.StrictMode>
<Provider store={store}>
<App/>
</Provider>
</React.StrictMode>,
)
4、React 元件使用 store 中的資料
在 React 元件中使用 store 中的資料,需要用到一個鉤子函式 —
useSelector
,它的作用是把 store 中的資料對映到元件中,使用樣例如下:
.
5、React 元件修改 store 中的資料
React 元件中修改 store 中的資料需要藉助另外一個 hook 函式 —
useDispatch
,它的作用是生成提交 action 物件的 dispatch 函式,使用樣例如下:
.
Redux 與 React — 提交 action 傳參
需求:元件中有倆個按鈕
add to 10
和add to 20
可以直接把 count 值修改到對應的數字,目標 count 值是在元件中傳遞過去的,需要在提交 action 的時候傳遞引數。
.
實現方式:在 reducers 的同步修改方法中新增 action 物件引數,在呼叫 actionCreater 的時候傳遞引數,引數會被傳遞到 action 物件 payload 屬性上。
.
Redux 與 React — 非同步 action 處理
需求理解
.
實現步驟:
- 建立 store 的寫法保持不變,配置好同步修改狀態的方法
- 單獨封裝一個函式,在函式內部 return 一個新函式,在新函式中
2.1 封裝非同步請求獲取資料
2.2 呼叫同步 actionCreater 傳入非同步資料生成一個 action 物件,並使用 dispatch 提交 - 元件中 dispatch 的寫法保持不變
.
程式碼實現:
channelStore.js
import {createSlice} from "@reduxjs/toolkit"
import axios from "axios"
const channelStore = createSlice({
name: "channel",
initialState: {
channelList: [],
},
reducers: {
setChannelList(state, action) {
state.channelList = action.payload
},
},
})
// 建立非同步
const {setChannelList} = channelStore.actions
const url = "http://geek.itheima.net/v1_0/channels"
// 封裝一個函式,在函式中 return 一個新函式,在新函式中封裝非同步
// 得到資料之後透過 dispatch 函式觸發修改
const fetchChannelList = () => {
return async (dispatch) => {
const res = await axios.get(url)
dispatch(setChannelList(res.data.data.channels))
}
}
export {fetchChannelList}
const channelReducer = channelStore.reducer
export default channelReducer
App.jsx
import {useDispatch, useSelector} from "react-redux"
import {fetchChannelList} from "./store/modules/channelStore.js"
import {useEffect} from "react"
const App = () => {
// 使用資料
const {channelList} = useSelector(state => state.channel)
const dispatch = useDispatch()
useEffect(() => {
dispatch(fetchChannelList())
}, [dispatch])
return (
<>
{channelList.map(channelItem => <li key={channelItem.id}>{channelItem.name}</li>)}
</>
)
}
export default App
Redux 除錯 — devtools
Redux 官方提供了針對於 Redux 的除錯工具,支援實時 state 資訊展示,action 提交資訊檢視等
.