網站首頁 編程語言 正文
一、Redux
和vuex一樣,redux的出現是為了管理web應用的公共狀態。
這些 state 可能包括服務器響應、緩存數據、本地生成尚未持久化到服務器的數據,也包括 UI 狀態,如激活的路由,被選中的標簽,是否顯示加載動效或者分頁器等等。
二、Redux的組成
2.1 store
store 就是保存數據的地方,整個應用只能有一個 store,可以理解為一個存儲數據的倉庫。
redux 提供 createStore
這個函數,用來創建一個store 以存放整個應用的 state:
import { createStore } from 'redux'; const store = createStore(reducer, [preloadedState], [enhancer]);
可以看到,createStore
接受 reducer
、初始 state(可選)
和增強器(可選)作為參數,返回一個新的 store 對象
.
2.2 state
state就是store 對象包含所有數據,如果要獲取當前時刻的 state,可以通過 store.getState() 方法拿到:
import { createStore } from 'redux'; const store = createStore(reducer, [preloadedState], [enhancer]); const state = store.getState();
2.3 action
- state 的變化,會導致視圖的變化。但是,用戶接觸不到 state,只能接觸到視圖。所以,state 的變化必須是由視圖發起的。
- action 就是視圖發出的通知,通知store此時的 state 應該要發生變化了。
- action 是一個對象。其中的 type屬性是必須的,表示 action 的名稱。其他屬性可以自由設置,社區有一個規范可以參考:
const action = { type: 'ADD_TODO', payload: 'Learn Redux' // 可選屬性 可自定義名稱 };
所以action可以理解為視圖層向store發送的一個命令(通知),它包含了需要執行的事件(type屬性)以及傳遞的數據(自定義屬性)。
2.4 reducer
- store 收到 action 以后,必須給出一個新的 state,這樣視圖才會進行更新。state 的計算(更新)過程則是通過reducer 實現。
- reducer 是一個函數,它接受 action 和當前 state 作為參數,返回一個新的 state:
const reducer = function (state = initState, action) { // ... return new_state; };
創建store時,第一個參數就是reducer:
const store = createStore(reducer);
那么如何向store發送action呢?
store.dispatch({ type: 'ADD_TODO', payload: 'Learn Redux' });
store對象擁有dispath
方法發送action,參數就是需要傳遞的action對象,然后reducer接收到action并處理,返回新的state,視圖自動更新。
三、三大原則
Redux 可以用這三個基本原則來描述:
3.1 單一數據源
整個應用的 state 被儲存在一棵 object tree
中,并且這個 object tree 只存在于唯一一個 store 中。
console.log(store.getState()) /* 輸出 { visibilityFilter: 'SHOW_ALL', todos: [ { text: 'Consider using Redux', completed: true, }, { text: 'Keep all state in a single tree', completed: false } ] } */
3.2 State只讀
唯一改變 state 的方法就是觸發 action
,action 是一個用于描述已發生事件的普通對象。
這樣確保了視圖和網絡請求都不能直接修改 state,相反它們只能表達想要修改的意圖。因為所有的修改都被集中化處理,且嚴格按照一個接一個的順序執行,因此不用擔心競態條件(race condition)的出現。 Action 就是普通對象而已,因此它們可以被日志打印、序列化、儲存、后期調試或測試時回放出來。
store.dispatch({ type: 'COMPLETE_TODO', index: 1 }) store.dispatch({ type: 'SET_VISIBILITY_FILTER', filter: 'SHOW_COMPLETED' })
所以返回新的state時不能直接修改參數state,而是在不修改參數state的基礎上返回新的state。
例如完成一個新增todo的功能:
case 'ADD_TODO': return state.push({ text: action.text, completed: false })
這樣是不會生效的,應為這樣直接修改了state的值,正確的做法應該是:
case 'ADD_TODO': return [ ...state, { text: action.text, completed: false } ]
這里使用了擴展運算符(…)將數組展開然后和新增的todo合并,對象同樣可以使用擴展運算符達到新增屬性的目的。
3.3 使用純函數修改State
為了描述 action 如何改變 state tree ,你需要編寫 reducers
。
Reducer 只是一些純函數,它接收先前的 state
和 action
,并返回新的 state。剛開始你可以只有一個 reducer,隨著應用變大,你可以把它拆成多個小的 reducers,分別獨立地操作 state tree 的不同部分,因為 reducer 只是函數,你可以控制它們被調用的順序,傳入附加數據,甚至編寫可復用的 reducer 來處理一些通用任務,如分頁器。
function visibilityFilter(state = 'SHOW_ALL', action) { switch (action.type) { case 'SET_VISIBILITY_FILTER': return action.filter default: return state } } function todos(state = [], action) { switch (action.type) { case 'ADD_TODO': return [ ...state, { text: action.text, completed: false } ] case 'COMPLETE_TODO': return state.map((todo, index) => { if (index === action.index) { return Object.assign({}, todo, { completed: true }) } return todo }) default: return state } } import { combineReducers, createStore } from 'redux' //合并reducer let reducer = combineReducers({ visibilityFilter, todos }) //利用reducer創建store let store = createStore(reducer)
四、基于Redux的TodoList
效果:
todes的reducer:
const initTodos = [ { id: 1, text: "睡覺??", completed: false, }, { id: 2, text: "吃飯??", completed: false, }, { id: 3, text: "打豆豆??", completed: true, }, ]; let nextTodoID = 4; const todos = (state = initTodos, action) => { switch (action.type) { case "ADD_TODO": return [ ...state, { id: nextTodoID++, text: action.text, completed: false, }, ]; case "TOGGLE_TODO": return state.map((todo) => todo.id === action.id ? { ...todo, completed: !todo.completed } : todo ); default: return state; } }; export default todos;
filter的reducer:
const visibilityFilter = (state = "SHOW_ALL", action) => { switch (action.type) { case "SET_VISIBILITY_FILTER": return action.filter; default: return state; } }; export default visibilityFilter;
詳細代碼地址:
https://github.com/YancyZhang30/react-redux-todos.git
五、react-redux
redux 并不是react專有的,其本身是一個可以結合 react,vue,angular 甚至是原生 javaScript 應用使用的狀態庫。
react-redux是react官方提供了 react的redux適配庫(這個庫是可以選用的,也可以只用redux),使得我們能夠更好地在react應用中使用redux來進行全局狀態管理,使用react-redux主要是為了解決組件每次使用store中的數據時都必須先使用store.getState()
來獲取state,然后必須使用store.subscribe()
進行訂閱的問題。
react-redux 將所有組件分成 UI 組件和容器組件兩大類:
1、 UI 組件只負責 UI 的呈現,不含有狀態(this.state),所有數據都由 this.props
提供,且不使用任何 redux 的 API。
2、容器組件負責管理數據和業務邏輯,含有狀態(this.state),可使用 redux 的 API。
5.1 connect方法
react-redux 提供了 connect 方法,用于將 UI 組件生成容器組件,所以如果組件想要使用store中的state,就必須先使用connect方法與store進行連接:
import {connect} from 'react-redux' const Counter = (props) => { return ( <div> <p>計數器: {props.num}</p> <div> <button onClick={props.increatement}>加</button> | <button onClick={props.decreate}>減</button><br/> </div> </div> ) } //讀取數據 const mapStateToProps=(state)=>{ return{ num:state } } //進行觸發action const mapDispathToProps=(dispatch)=>{ return { increatement:()=>{dispatch( { type:"inCreateNum", num:10 } )}, decreate:()=>{dispatch( { type:"descment", num:10 } )} } } // connect將組件與store連接。connect里的參數順序不能顛倒 export default connect(mapStateToProps,mapDispathToProps)(Counter)
connect(mapStateToProps,mapDispathToProps)(Counter)
中:
- mapStateToProps:mapStateToProps 是一個函數,它的作用就是建立一個從 state對象(外部)到 UI 組件 props對象的映射關系。該函數會訂閱 整個應用的 store,每當 state 更新的時候,就會自動執行,重新計算 UI 組件的參數,從而觸發 UI 組件的重新渲染。還可以使用第二個參數(可選),代表容器組件的 props 對象
- mapDispathToProps:mapDispatchToProps 是 connect 函數的第二個參數,用來建立 UI 組件的參數到 store.dispatch 方法的映射。
- Counter:需要變成容器組件的UI組件,也就是需要連接store的組件。
5.2 Provider組件
- 使用 connect 方法生成容器組件以后,需要讓容器組件拿到 state 對象,才能生成 UI 組件 的參數。
- react-redux提供了 Provider 組件,可以讓容器組件拿到 state,注意只有被Provider組件包含的組件才能拿到state。
main.jsx:
import React from 'react' import ReactDOM from 'react-dom/client' import { Provider } from 'react-redux' import Counter from "./Counter"; import ShowCounter from "./ShowCounter"; import reducer from "./store/counter"; import { legacy_createStore as createStore } from "redux"; const store = createStore(reducer); ReactDOM.createRoot(document.getElementById('root')).render( <Provider store={store}> <React.StrictMode> <Counter></Counter> <ShowCounter></ShowCounter> </React.StrictMode> </Provider> )
此時Counter組件和ShowCounter組件都可以拿到state。
ShowCounter.jsx:
import React from "react"; import {connect} from "react-redux"; const ShowCounter = (props) => { return ( <div> <p>來自計數器的數據:<span style={{color: 'red'}}>{props.num}</span></p> </div> ) } //讀取數據 const mapStateToProps=(state)=>{ return{ num:state } } // connect將組件與store連接。connect里的參數順序不能顛倒 export default connect(mapStateToProps)(ShowCounter)
由于ShowCounter組件并不需要修改store,所以mapDispathToProps參數可以直接省略了。
效果:
原文鏈接:https://blog.csdn.net/ZHANGYANG_1109/article/details/125953507
相關推薦
- 2022-05-12 C語言的數組指針與函數指針詳解_C 語言
- 2023-11-15 latex報錯:Misplaced alignment tab character &. .
- 2022-07-09 嵌入式linux使用trace調試步驟記錄
- 2022-03-14 Springboot中遇到的問題——Failed to load ApplicationContex
- 2022-05-25 Properties與ResourceBundle的基本使用以及區別
- 2022-11-23 shell腳本設置日志格式的方法_linux shell
- 2023-01-11 Rust結構體的定義與實例化詳細講解_Rust語言
- 2023-03-18 pandas檢查和填充缺失值的N種方法總結_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支