React18學習筆記(二) React的狀態管理工具--Redux,案例--移動端外賣平臺

文章目錄

      • 一.Redux的基礎用法
        • 1.示例:普通網頁中的Redux計步器
        • 2.Redux管理數據的流程
        • 3.配套工具和環境準備
          • 3.1.配套工具
          • 3.2.環境準備
        • 4.示例:React項目中的Redux計步器
          • 思路
          • 步驟
            • step1:創建子模塊
            • step2:導入子模塊
            • step3:注入store實例
            • step4:React組件內使用store中的數據
            • step5:在組件內修改store中的數據
            • step6:優化---定義代參actionCreater來傳參
        • 5.示例:使用Redux管理異步狀態操作
          • 5.1.創建子模塊
          • 5.2.導入子模塊
          • 5.3.注入store實例
          • 5.4.在組件中使用
      • 二.Redux案例:某團外賣
        • 1.開發前準備
        • 2.渲染商品分類和商品列表
          • 2.1.創建子模塊takeaway
          • 2.2.引入子模塊
          • 2.3.把store注入到組件中
          • 2.4.在根組件App中使用和渲染數據
        • 3.點擊分類實現高亮
          • 3.1.RTK管理新狀態activeIndex
          • 3.2.組件中:點擊觸發action更新activeIndex,動態控制激活類名
        • 4.點擊分類項,實現商品列表的切換顯示

一.Redux的基礎用法

Redux之于React,類似于Vuex或Pinia之于Vue
Redux可以獨立于框架運行,作用是通過幾種管理的方式管理應用的狀態

1.示例:普通網頁中的Redux計步器

由于Redux可以獨立于React框架,因此可在網頁中使用
步驟:

-step1:定義一個reducer函數
該函數根據當前想要做的修改返回一個新狀態,新狀態的作用是根據不同的Action對象,返回不同的新state(原則:狀態不可變)
示例:function myReducer(state,action){}-step2:使用createStore方法中的reducer函數生成一個store實例對象
示例:const store=Redux.createStore(myReducer)-step3:使用store.subscribe方法,訂閱數據的變化
(數據一旦變化就會得到通知)
示例:storesubscribe(()=>{})-step4:使用store.dispatch方法,提交action對象,觸發數據變化
dispatch提交一個action來更新狀態
示例:store.dispatch({type:'INCREMENT'})-step5:使用store.getState方法,獲取最新的狀態并更新到視圖中
示例:const state=stor.getState()

完整代碼:

<!DOCTYPE html>
<html>
<head><title>Redux計數器示例</title><!-- 引入Redux庫 --><script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.2.1/redux.min.js"></script>
</head>
<body><h1>Redux計數器</h1><div><button id="decrement">-</button><span id="counter-value">0</span><button id="increment">+</button></div><script>// 1.定義reducer函數function myReducer(state = { count: 0 }, action) {// 判斷type:type的值是從action對象中獲取的,而action對象是由dispatch函數生成的。if (action.type === 'INCREMENT') return { count: state.count + 1 };//增加:返回新的狀態對象if (action.type === 'DECREMENT') return { count: state.count - 1 };}// 2.使用reducer函數生成store實例const store = Redux.createStore(myReducer);// 3.通過store實例的subscribe訂閱數據變化store.subscribe(() => {//該回調會在每次store更新時被調用。// 5.通過store實例的getState方法獲取當前狀態值,并更新到頁面上。const state = store.getState();// 更新頁面上的計數器顯示document.getElementById('counter-value').textContent = state.count;});// 4.通過store實例的dispatch函數提交action更改狀態/*在Redux中修改數據的唯一方式是:通過dispatch提交一個action對象來更新狀態*/document.getElementById('increment').addEventListener('click', () => {store.dispatch({ type: 'INCREMENT' });// 提交增加計數器的action對象});document.getElementById('decrement').addEventListener('click', () => {store.dispatch({ type: 'DECREMENT' });// 提交減少計數器的action對象});</script>
</body>
</html>
2.Redux管理數據的流程

在這里插入圖片描述
出于職責清晰和數據流向明確的考量,在Redux中,把修改數據的流程分為三個核心概念:

  • state對象:存放管理的數據狀態
  • action對象:描述如何修改數據的
  • reducer函數:形參是state和action,根據acton對象的描述生成一個新的state
3.配套工具和環境準備
3.1.配套工具
  • Redux Toolkit插件(RTK)

官方推薦的編寫Redux邏輯的方式,是一套工具的集合,能簡化書寫方式

優點:簡化store的配置方式內置immer支持可變式狀態修改內置thunk更好的異步創建
  • react-dedux插件

用來鏈接Redux和React組件的中間件
(Redux向React組件獲取狀態,React組件向Redux更新狀態,都可以通過這個中間件)

3.2.環境準備

創建項目:npx create-react-app my-react-redux(項目名)
進入項目目錄:cd my-react-redux
安裝配套工具:npm i @reduxjs/toolkit react-redux(插件)
啟動項目:npm run start

項目store目錄:

src
├─store               用于集中狀態管理
│  ├─modules		用于在內部編寫業務分類的子store(應用通常有多個子store模塊)
│  │  └─index.js      作用是組合modules中的所有子模塊并在store中導入 
4.示例:React項目中的Redux計步器
思路
  • Redux store配置:配置counterStore模塊,配置根store并導入counterStore模塊
  • React組件:注入store(react-redux),使用和修改store中的數據
步驟
step1:創建子模塊

使用React ToolkitcreateSlice()方法創建counterStore子模塊

//store/modules/counterStore.jsimport {createSlice} from "@reduxjs/toolkit";
const counterstore=createSlice({name:"counter",// 初始化stateinitialState:{//----類似于Vuex中的Storecount:0},// 定義reducer函數reducers:{//----類似于vuex中的mutationsincrement(state){state.count++},decrement(state){state.count--}}
})// 解構出actionCreater函數
const {increment,decrement}=counterstore.actions
// 獲取reducer函數
const reducer=counterstore.reducer
// 按需導出actionCreater函數
export {increment,decrement}
// 默認導出reducer函數
export default reducer
step2:導入子模塊
//src/store/index.jsimport { configureStore } from "@reduxjs/toolkit";
// 導入子模塊的reducer
import counterReducer from "./modules/counterStore";
export const store = configureStore({reducer: {// 注冊子模塊的reducer函數counter: counterReducer,},
});
step3:注入store實例

react-redux可以鏈接Redux和React,
其內置的Provider組件可以通過store參數,把創建好的store實例注入到應用中,從而正式建立鏈接

//src/index.jsimport { Provider } from 'react-redux';
import { store } from './store';
....{/* 注入:將store注入到Provider組件的props中,然后包裹App組件。 */}<Provider store={store}><App /></Provider>
step4:React組件內使用store中的數據

鉤子函數useSelector可以把store中的數據映射到組件中

//App.jsimport { useSelector } from "react-redux";
function App() {const { count } = useSelector((state) => state.counter);//來自src/store/index.js的reducer函數return (<div className="App"><h1>Counter: {count}</h1></div>);
}
export default App;
step5:在組件內修改store中的數據

鉤子函數useDispatch可以生成dispatch函數,用于提交action對象

//App.js
// 導入actionCreater
import {increment,decrement} from "./store/modules/counterStore";{/* 增加按鈕,觸發 increment action */}
<button onClick={() => dispatch(increment())}>+</button>
{/* 顯示計數器 */}
<h1>Counter: {count}</h1>
{/* 減少按鈕,觸發 decrement action */}
<button onClick={() => dispatch(decrement())}>-</button>

*子模塊counterStore中,在reducers中定義的increment()decrement()被稱為actionCreater方法

step6:優化—定義代參actionCreater來傳參

App組件新增"addTo10"和"addTo20"兩個按鈕,
步驟:
* 在reducers的同步修改方法中添加action對象參數
* 在調用actionCreater時傳參
* 參數傳到action對象的payload屬性上
代碼:

//counterStore.js
.....// 定義reducer函數reducers:{...addToNum(state,action){state.count+=action.payload}}
// 解構出actionCreater函數
const {increment,decrement,addToNum}=counterstore.actions
// 獲取reducer函數
const reducer=counterstore.reducer
// 按需導出actionCreater函數
export {increment,decrement,addToNum}
// 默認導出reducer函數
export default reducer//App.js
import {increment,decrement,addToNum} from "./store/modules/counterStore";<button onClick={() => dispatch(addToNum(10))}>+10</button><button onClick={() => dispatch(addToNum(20))}>+20</button>

總結:

  • useSelector:獲取store中的數據
  • useDispatch:獲取dispatch方法
  • 得到要提交的action對象:dispatch(increment())//執行store模塊中導出的actionCreater方法,即increment()方法
5.示例:使用Redux管理異步狀態操作
5.1.創建子模塊
//新建store/modules/channelStore.js//step1:創建子模塊channelStore.js,代碼不變
import { createSlice } from "@reduxjs/toolkit";
import axios from "axios";const channelstore=createSlice({name:'channel',initialState:{channelList:[]},reducers:{setChannel(state,action){state.channelList=action.payload}}
})/**異步請求部分 */
// step2:單獨封裝一個函數
const fetchChannelList=()=>{// const dispatch=useDispatch()// 在函數內部return一個新函數,// 在新函數中封裝異步請求,// 并調用actionCreater方法傳入異步數據生成一個action對象并使用dispatch方法提交return async (dispatch)=>{const res=await axios.get("https://geek.itheima.net/v1_0/channels")dispatch(setChannel(res.data.data.channels))console.log("res:",res.data.data.channels)}
}// 解構出actionCreater函數
const {setChannel}=channelstore.actions
// 按需導出actionCreater函數和異步請求函數
export {setChannel,fetchChannelList}// 獲取reducer函數
const reducers=channelstore.reducer
// 默認導出reducer函數
export default reducers
5.2.導入子模塊
//store/index.js
import { configureStore } from "@reduxjs/toolkit";
// 導入子模塊的reducer
import counterReducer from "./modules/counterStore";
import channelReducer from "./modules/channelStore";
export const store = configureStore({reducer: {// 注冊子模塊的reudcer函數counter: counterReducer,channel: channelReducer,},
});
5.3.注入store實例

略,無新增代碼

5.4.在組件中使用
//App.js
import { fetchChannelList } from "./store/modules/channelStore";
import { useEffect } from "react";function App(){// 使用 dispatch 來觸發 actionconst dispatch = useDispatch();// 使用useEffect來觸發異步請求執行useEffect(() => {// 觸發 fetchChannelList actiondispatch(fetchChannelList());}, [dispatch]);return(<ul>{channelList.map((item) => (<li key={item.id}>{item.name}</li>))}</ul>)
}

二.Redux案例:某團外賣

在這里插入圖片描述
功能:

	* 1.商品列表和分類渲染* 2.添加商品* 3.購物車操作* 4.訂單數量統計和高亮實現

思路:
???? 使用Redux Toolkit(RTK)來管理應用狀態,
?????組件負責數據渲染和dispatch action

1.開發前準備
step1:從遠程倉庫克隆本地git clone http://git.itcast.cn/heimaqianduan/redux-meituan.git
step2:安裝所有依賴npm i
step3:啟動mock服務(內置json-server)npm run serve
step4:啟動前端服務npm run start
2.渲染商品分類和商品列表
2.1.創建子模塊takeaway
//store/modules/takeaway.js
import { createSlice } from "@reduxjs/toolkit";
import axios from "axios";const foodsStore = createSlice({name: "foods",initialState: { foodsList: [] },reducers: {setFoodsList(state, action) {state.foodsList = action.payload;}}
})// 解構createAction方法
const { setFoodsList } = foodsStore.actions// 異步
const fetchFoodsList = () => {return async (dispatch) => {// 獲取數據const res = await axios.get("http://localhost:3004/takeaway");// dispatch提交,生成新的action對象dispatch(setFoodsList(res.data))}
}// 按需導出
export { setFoodsList, fetchFoodsList }// 獲取reducer
const reducer = foodsStore.reducer
// 默認導出
export default reducer
2.2.引入子模塊
//src/store/index.js import { configureStore } from "@reduxjs/toolkit";
// 導入子模塊的reducer
import foodsReducer from "./modules/takeaway";export default configureStore({reducer: {// 這里的key要和子模塊的name一致foods: foodsReducer,},
});
2.3.把store注入到組件中
//index.jsimport { createRoot } from 'react-dom/client'
import {Provider} from 'react-redux'
import App from './App'
import store from './store'const root = createRoot(document.getElementById('root'))
root.render(// 注入:把store注入到Provider組件中,然后包裹App組件<Provider store={store}><App /></Provider>
)
2.4.在根組件App中使用和渲染數據
//App.js
import { useDispatch,useSelector } from 'react-redux'
import { useEffect } from 'react'
import { fetchFoodsList } from './store/modules/takeaway'//注釋掉靜態數據const foodsList=[]const App=()=>{/*觸發action執行*/const dispatch=useDispatch()// 使用useEffect鉤子,在組件加載完成后獲取外賣商品列表useEffect(()=>{dispatch(fetchFoodsList())// 派發一個異步獲取外賣商品列表的action},[dispatch])/*獲取foodsList渲染數據列表*/// 使用useSelector鉤子獲取foodsList數據const {foodsList} = useSelector(state => state.foods)
}
3.點擊分類實現高亮

即點擊左邊側邊欄中的分類獲得高亮選中,右邊的對應內容在頁面中渲染

高亮和對應的內容如何綁定?

  • 記錄當前的點擊項activeIndex
  • 動態控制類名,判斷條件activeIndex===index

步驟:
????1.RTK管理新狀態activeIndex
????2.組件中點擊觸發action,更改activeIndex
????3.動態控制激活類名顯示

3.1.RTK管理新狀態activeIndex
//store/modules/takeaway.jsconst foodsStore = createSlice({name: "foods",initialState: {foodsList: [] ,//菜單列表activeIndex: 0 // 當前激活的菜單索引},reducers: {.....// 更改當前激活的菜單索引changeActiveIndex(state, action) {state.activeIndex = action.payload;}}
})
// 解構createAction方法
const { setFoodsList ,changeActiveIndex} = foodsStore.actions
// 按需導出
export { fetchFoodsList, changeActiveIndex }
3.2.組件中:點擊觸發action更新activeIndex,動態控制激活類名
//src/components/menus/index.jsimport classNames from 'classnames'
import './index.scss'
import { useSelector, useDispatch } from 'react-redux'
import { useEffect } from 'react'
import { changeActiveIndex } from '../../store/modules/takeaway'const Menu = () => {// 從redux中獲取數據
const { foodsList,activeIndex} = useSelector((state) => state.foods);
////過濾條件: 過濾出所有標簽,并且去除重復的
const menus=foodsList.map(item=>({tag:item.tag,name:item.name}))
const dispatch = useDispatch()// 使用useEffect觸發actionuseEffect(() => {dispatch(changeActiveIndex(0))//初始值讓渲染有默認選中}, [dispatch])return (<nav className="list-menu">{/* 添加active類名會變成激活狀態 */}{menus.map((item, index) => {return (<divonClick={() => {dispatch(changeActiveIndex(index))}}key={item.tag}className={classNames('list-menu-item',activeIndex===index&&'active')}>{item.name}</div>)})}</nav>)
}
export default Menu
4.點擊分類項,實現商品列表的切換顯示

條件渲染,控制對應項的顯隱activeIndex===index&&<div></div>

//App.js
const { foodsList, activeIndex } = useSelector(state => state.foods)
....
{/* 外賣商品列表 */}
{foodsList.map((item, index) => {return (activeIndex === index && <FoodsCategorykey={item.tag}// 列表標題name={item.name}// 列表商品foods={item.foods}/>)
})}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/98018.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/98018.shtml
英文地址,請注明出處:http://en.pswp.cn/web/98018.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

34.Socket編程(UDP)(上)

點分十進制字符串IP 轉 32位網絡序列IP 分析&#xff1a;1&#xff09;IP轉成4字節 2&#xff09;4字節轉成網絡序列 思路&#xff1a; "192.168.1.1" 進行字符串劃分&#xff0c;以 "." 為分割符&#xff0c;分割出"192"&#xff0c;&qu…

Redis的持久化工具包—RDB AOF

文章目錄 前言 一、RDB 持久化&#xff08;快照持久化&#xff09; 1. 定義 2. RDB 觸發機制 &#xff08;1&#xff09;手動觸發 &#xff08;2&#xff09;自動觸發 3. RDB 持久化流程 4. RDB 核心配置 5. RDB 優缺點 二、AOF 持久化&#xff08;日志持久化&#xff09; 1. 定…

【Web安全】XXL-JOB框架SRC高頻漏洞分析總結

文章目錄前言一、核心漏洞分類與技術細節二、漏洞關聯利用與攻擊路徑三、版本演進與修復策略四、安全運維建議五、典型漏洞復現環境搭建六、總結前言 XXL-JOB是國內主流的開源分布式任務調度框架&#xff0c;由徐雪里開發維護&#xff0c;以輕量易用、高可用、適配分布式場景等…

Capacitor 打包后接口訪問不到的排查經歷

我最近在用 Quasar Capacitor 6 做一個 Android App&#xff0c;前端用的是 Vue3 Quasar&#xff0c;打包交給 Capacitor 去跑在手機的 WebView 里&#xff0c;后端是 FastAPI 提供接口。開發模式下一切順利&#xff0c;瀏覽器里訪問接口沒有任何問題&#xff0c;我甚至覺得打…

【正點原子】Linux應用編程入門~概念及環境介紹

應用編程概念 應用編程&#xff08;也可稱為系統編程&#xff09;與驅動編程、裸機編程有何不同&#xff1f;系統調用&#xff1b;何為庫函數&#xff1b;應用程序的 main()函數&#xff1b;應用程序開發環境的介紹&#xff1b;系統調用 定義系統調用&#xff08;system call&a…

一、HTML 完全指南:從零開始構建網頁

文章目錄前言一、 HTML 結構認識 HTML 標簽HTML 文件基本結構標簽層次結構快速生成代碼框架二、 HTML 常見標簽詳解2.1 注釋標簽2.2 標題標簽 (h1 - h6)2.3 段落標簽 (p)2.4 換行標簽 (br)2.5 格式化標簽2.6 圖片標簽 (img)2.7 超鏈接標簽 (a)2.8 表格標簽基本使用合并單元格2.…

基于POI-TL實現動態Word模板的數據填充:【散點圖】特殊處理方案

基于POI-TL實現動態Word模板的數據填充:散點圖特殊處理方案 在使用POI-TL進行Word模板動態數據填充時,圖表生成是一個常見需求。最近在項目中使用POI-TL處理散點圖時遇到了一個特殊問題,經過研究后找到了解決方案,特此記錄分享。 問題背景 POI-TL作為一款優秀的Java Wor…

使用node-Express框架寫一個學校宿舍管理系統練習項目-前后端分離

今天繼續分享一個新的練習項目&#xff0c;是使用node做為后端語言&#xff0c;來寫的一個前后端分離項目&#xff1a;學校宿舍管理系統。我們如果想掌握一門編程語言&#xff0c;就是需要大量的練習。所以當我們學習到了一些知識&#xff0c;自己想一下 可以拿學到的知識&…

Kafka 運維實戰基本操作含命令與最佳實踐

1. 基礎概覽與工具入口 Kafka 發行包的所有 CLI 工具均在 bin/ 目錄下。任何工具不帶參數運行都會顯示所有可用選項。本文命令默認&#xff1a;--bootstrap-server localhost:9092&#xff1b;生產請替換為你的控制面或內網 VIP。 2. 主題管理&#xff08;創建 / 修改 / 刪除 /…

貪心算法應用:航班起降問題詳解

Java中的貪心算法應用&#xff1a;航班起降問題詳解 貪心算法是一種在每一步選擇中都采取當前狀態下最優的選擇&#xff0c;從而希望導致全局最優解的算法策略。在航班起降問題中&#xff0c;貪心算法可以有效地解決機場跑道調度問題&#xff0c;即如何安排航班的起降順序以最大…

uniapp scroll-view 設置scrollTop無效

當我們使用 scroll-view的scroll-top的時候 默認想讓它回到頂部&#xff0c;當我們設置值為0的時候會不生效&#xff0c;在實際運用過程中&#xff0c;發現設置了scroll-top無效&#xff0c;滾動條位置并沒有發生變化&#xff0c;是因為微信小程序的官方框架處于性能考慮&#…

網絡與通信

1.TCP協議與UDP協議TCP&#xff08;Transmission Control Protocol&#xff0c;傳輸控制協議&#xff09;和 UDP&#xff08;User Datagram Protocol&#xff0c;用戶數據報協議&#xff09;是 TCP/IP 協議族中兩種核心的傳輸層協議&#xff0c;它們在數據傳輸方式、可靠性、適…

Node.js中package.json詳解

1. name&#xff08;名稱&#xff09; 如果你計劃發布你的包&#xff0c;package.json 中最重要的字段是 name 和 version&#xff0c;因為它們是必需的。name 和 version 共同組成一個假定完全唯一的標識符。包的更改應伴隨版本號的更新。如果你不打算發布包&#xff0c;那么…

代碼隨想錄第14天| 翻轉、對稱與深度

226.翻轉二叉樹 &#xff08;優先掌握遞歸&#xff09; 題目鏈接/文章講解/視頻講解&#xff1a;翻轉二叉樹 交換的是指針&#xff0c;而不是數值&#xff0c;如果用數值做交換&#xff0c;需要交換的節點下面無法很好的操作。 使用遞歸來實現&#xff0c;但要提前清除是什么順…

DNS-Windows上使用DNS

DNS-Windows上使用DNS一、查看與修改DNS配置1.1、查看當前DNS服務器設置1.2、臨時修改 DNS 服務器&#xff08;命令行&#xff09;二、DNS緩存相關操作2.1、查看DNS緩存內容2.2、 刷新 DNS 緩存&#xff08;清除過期記錄&#xff09;三、測試域名解析&#xff08;nslookup 工具…

3dsMax 2026 .NET Core 8 轉型下的Maxscript腳本開發:動態編譯模塊的重構策略與兼容性升級路徑

3ds Max 長期以來一直提供出色的 .NET 集成,使 Maxscript 能夠無縫利用任何 .NET 庫的強大功能。部分開發者在工具中廣泛使用了 .NET 功能。 之前,3ds Max 依賴于 .NET Framework 4.8 并且最近更新到了 4.8.1,用于 2025 版本的發布。然而,隨著 3ds Max 2026 的推出,Autod…

golang 做webrtc開發核心

在Golang中進行WebRTC開發&#xff0c;核心在于理解WebRTC協議的工作原理以及如何利用Go生態中的庫來實現關鍵功能。以下是Golang WebRTC開發的核心要點&#xff1a; WebRTC基礎概念 了解ICE&#xff08;Interactive Connectivity Establishment&#xff09;協議用于NAT穿越掌握…

RabbitMQ 異步化抗洪實戰

說明&#xff1a;本文僅展示架構思路與安全片段&#xff0c;所有敏感字段已用占位符&#xff1b;不含可直接復刻的生產細節。數據與接口均為演示/虛擬。0. 背景與目標長耗時/不確定接口&#xff08;如對接第三方機器人平臺&#xff09;的同步阻塞&#xff0c;容易造成請求堆積與…

接口返回 2 萬條數據,easy-trans導致多了20s耗時排查過程

內網訪問排版核料詳情功能&#xff0c;用戶反饋要等十幾秒排查 sql&#xff1a;sql 比較簡單排查內存計算&#xff1a;arthus trace 類名 方法名 總耗時2s排查頁面渲染是否緩慢&#xff1a;F12 查看接口 等待服務器響應 20s 下載時間 30s, 故不考慮渲染問題排查請求響應日志打…

AIGC入門,手搓大模型客戶端與MCP交互

概述 在現代應用開發中&#xff0c;將大語言模型&#xff08;LLM&#xff09;與專用工具服務相結合&#xff0c;可以構建出既能理解自然語言&#xff0c;又能準確執行專業任務的智能代理。本文介紹一個基于 MCP&#xff08;Model Context Protocol&#xff09;協議和 Ollama 本…