Redux

软柠柠吖發表於2024-03-10

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),可以獨立於框架執行。
作用:透過集中管理的方式管理應用的狀態。

image-20240227174903972.

為什麼要使用 Redux ?

  1. 獨立於元件,無視元件之間的層級關係,簡化通訊問題;
  2. 單項資料流清晰,易於定位 bug;
  3. 除錯工具配套良好,方便除錯。

1、實現計數器

需求:不和任何框架繫結,不使用任何構建工具,使用純 Redux 實現計數器。

image-20240227175003483.
使用步驟:

  1. 定義一個 reducer 函式 (根據當前想要做的修改返回一個新的狀態)
  2. 使用 createStore 方法傳入 reducer 函式 生成一個 store 例項物件
  3. 使用 store 例項的 subscribe 方法 訂閱資料的變化(資料一旦變化,可以得到通知)
  4. 使用 store 例項的 dispatch 方法提交 action 物件 觸發資料變化(告訴 reducer 你想怎麼改資料)
  5. 使用 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 的難點是理解它對於資料修改的規則,下圖動態展示了在整個資料的修改中,資料的流向:

image-20240227175150324.

為了職責清晰,資料流嚮明確,Redux 把整個資料修改的流程分成了三個核心概念,分別是:stateactionreducer

  1. state:一個物件,存放著我們管理的資料
  2. action:一個物件,用來描述你想怎麼改資料
  3. reducer:一個函式,根據 action 的描述生成一個新的 state


Redux 與 React — 環境準備

Redux 雖然是一個框架無關可以獨立執行的外掛,但是社群通常還是把它與 React 繫結在一起使用,以一個計數器案例體驗一下 Redux + React 的基礎使用


1、配套工具

在 React 中使用 redux,官方要求安裝 2 個其他外掛 — Redux Toolkitreact-redux

  1. Redux Toolkit(RTK)— 官方推薦編寫 Redux 邏輯的方式,是一套工具的集合集,簡化書寫方式

image-20240301182931016.

  1. react-redux — 用來連結 Redux 和 React 元件的中介軟體。

image-20240301182957832.


2、配置基礎環境

npm i @reduxjs/toolkit  react-redux

3、store 目錄結構設計

image-20240304144626654.

  1. 通常集中狀態管理的部分都會單獨建立一個單獨的 store 目錄

  2. 應用通常會有很多個子 store 模組,所以建立一個 modules 目錄,在內部編寫業務分類的子 store

  3. store 中的入口檔案 index.js 的作用是組合 modules 中所有的子模組,並匯出 store



Redux 與 React — 實現 counter


1、整體路徑熟悉

image-20240304145310693.


2、使用 React Toolkit 建立 counterStore

image-20240305195003606.

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 例項注入到應用中,連結正式建立。

image-20240304230206591.

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 中的資料對映到元件中,使用樣例如下:

image-20240305200416581.


5、React 元件修改 store 中的資料

React 元件中修改 store 中的資料需要藉助另外一個 hook 函式 — useDispatch,它的作用是生成提交 action 物件的 dispatch 函式,使用樣例如下:

image-20240305114411835.



Redux 與 React — 提交 action 傳參

需求:元件中有倆個按鈕 add to 10add to 20 可以直接把 count 值修改到對應的數字,目標 count 值是在元件中傳遞過去的,需要在提交 action 的時候傳遞引數。

image.png.

實現方式:在 reducers 的同步修改方法中新增 action 物件引數,在呼叫 actionCreater 的時候傳遞引數,引數會被傳遞到 action 物件 payload 屬性上。

image-20240305115457053.



Redux 與 React — 非同步 action 處理

需求理解
image.png.

實現步驟:

  1. 建立 store 的寫法保持不變,配置好同步修改狀態的方法
  2. 單獨封裝一個函式,在函式內部 return 一個新函式,在新函式中
    2.1 封裝非同步請求獲取資料
    2.2 呼叫同步 actionCreater 傳入非同步資料生成一個 action 物件,並使用 dispatch 提交
  3. 元件中 dispatch 的寫法保持不變

image-20240306085642506.

程式碼實現:

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 提交資訊檢視等

image-20240305120147913.

相關文章