JavaScript 的狀態容器 Redux
Redux
JavasSript 的狀態容器
跟 React 沒有關係,Redux 支援 React、Angular、Ember、JQuery 甚至 JavaScript。
Action、Reducer、Store
Redux
三大原則
單一資料來源
State 是可讀的
使用純函式來執行
Action
概念:
記錄了使用者行為的資料的載體
Action 是 Store 資料的唯一來源
定義:
Action 是一個 JavaScript 物件
Action 內有一個 Type 欄位
Action 通常被定義為字串常量
儘量減少在 Action 中傳遞的資料
設計 Todo 所需的 Action
var actionAddTodo = { type: 'ADD_TODO', text: '吃飯'};var actionCompleteTodo = { type:'COMPLETE_TODO', index:2};var actionSelectFilter = { type:'SETFILTER', filter:'SHOW_ALL'};
Action 函式
// 建立物件的工廠模式function createAction(text){ var o = new Object(); o.type = ADD_TODO; o.text = text; return o; }function addTodo(text){ return { type: 'ADD_TODO', text } }
State
概要
存放程式資料的一顆 ,或者說是一個資料庫。
State 是隻讀的,可能是一個 JavaScript 物件、陣列、Immutable.js 的資料結構
唯一能更新 State 的方法就是觸發 Action ,使用 Store 的 Dispatch 更新 State 。
為什麼強調 State 只讀
單一資料來源,State 是程式的唯一資料來源
確保檢視和網路請求只能表現出我想要修改 State , 然後透過觸發 Action 修改
只有唯一更新 State 方法,我們可以更容易的實現撤銷 / 重做這類應用
設計 State
Todo 的任務列表
var initState = { filter: 'SHOW_ALL', todos: [] }
設計 State 注意事項
應該儘量是 State 可以輕鬆的轉化為 JSON
儘可能把 State 規範化,不存在巢狀
把所有資料都放到一個物件裡,每個資料以 ID 作為主鍵
把 State 想象成一個資料庫
//方式一[{ id: 1, title: 'Some Article', author: { id: 1, name: 'Dan' } }, { id: 2, title: 'Other Article', author: { id: 1, name: 'Dan' } }]//方式二{ result: [1, 2], entities: { articles: { 1: { id: 1, title: 'Some Article', author: 1 }, 2: { id: 2, title: 'Other Article', author: 1 } }, users: { 1: { id: 1, name: 'Dan' } } } }
Object.assign(target,...source) 函式
把所有的源物件屬性複製到目標物件並放回。
// 用法一var o1 = {a:1};var o2 = {b:2};var o3 = {c:3};var obj1 = Object.assign(o1,o2,o3);console.log(o1); // {a:1,b:2,c:3}console.log(obj1); // {a:1,b:2,c:3}// 用法二var o4 = {a:1,b:2};var o5 = {b:3,c:4};var obj2 = Object.assign({},o4,o5);console.log(obj2); // {a:1,b:2,c:3,d:4}
怎麼使用 Object.assign()
必須保證 Reducer 是一個純函式,我們不能改變傳入的 State,所以我們需要使用 Object.assign({},state)
複製一個 State
var state = {filter:'SHOW_ALL',todos:['x1','x2']};var obj3 = Object.assign({},state,{todos:[state.todos[1],'x3']})console.log(obj3)
Reducer
var createStore = Redux.createStore;var combineReducers = Redux.combineReducers;var applyMiddleware = Redux.applyMiddleware;const ADD_TODO = 'ADD_TODO';const COMPLETE_TODO = 'COMPLETE_TODO';const SETFILTER = 'SETFILTER';const FILTER = { SHOW_ALL: 'SHOW_ALL', SHOW_COMPLETE: 'SHOW_COMPLETE', SHOW_ACTIVE: 'SHOW_ACTIVE'}function addTodo(text){ return { type: ADD_TODO, text } }function completeTodo(index){ return { type: COMPLETE_TODO, index } }function selectFilter(filter){ return { type: SETFILTER, filter } }var initState = { filter:'SHOW_ALL', todos: [] }function todoApp(state = initState,action){ switch(action.type){ case SETFILTER: return Object.assign({},state,{ filter: action.filter }); case ADD_TODO: return Object.assign({},state,{ todos:[...state.todos,{text: action.text,complete: false}] }); case COMPELETE_TODO: return Object.assign({},state,{ todos: return [ ...state.slice(0, parseInt(action.index), Object.assign({},state[action.index],{ completed: true }), ...state.slice(parseInt(action.index) + 1) ] }); default: return state; } }
拆分 Reducer
將不存在以來關係的欄位拆分給不同的子 Reducer 管理。
例如 Filter 和 Todos 倆個欄位不存在相互依賴。
function setFilter(state = FILTER.SHOW_ALL,action){ switch(action.type){ case SETFILTER: return action.filter; default: return state; } }function todos(state = [], action){ switch(action.type){ case ADD_TODO: return [...state, { text: action.type, completed: false }]; case COMPLETE_TODO: return [ ...state.slice(0,parse(action.index)), Object.assign({},state[action.index],{ completed: true }), ...state.slice(parseInt(action.index) + 1) ]; default: return state; } }
combineReducers 的使用
將每個 Reducer 拼接起來返回一個完整的 state
函式部分原始碼
// reducers -> Object// example -> reducers = { filter: setFilter, todos: todos}function combineReducers(reducers) { var reducerKeys = Object.keys(reducers) // array -> ['filter','todos'] var finalReducers = {} for (var i = 0; i使用例子
var todoApp = combineReducers({ filter: setFilter, todos: todos })Store
維持應用所有 State 的一個物件,也可是說一個方法的集合
var store = createStore(todoApp)Store 的方法
getState
dispatch 唯一能改變 state 的函式
subscribe 增加監聽,當 dispatch action 的時候就會觸發
replaceReducer 替換當前用來計算的 reducer
var createStore = Redux.createStore;var combineReducers = Redux.combineReducers;var applyMiddleware = Redux.applyMiddleware;const ADD_TODO = 'ADD_TODO';const COMPLETE_TODO = 'COMPLETE_TODO';const SETFILTER = 'SETFILTER';const FILTER = { SHOW_ALL:'SHOW_ALL', SHOW_COMPLETE:'SHOW_COMPLETE', SHOW_ACTIVE:'SHOW_ACTIVE'}function addTodo(text){ return { type:ADD_TODO, text } }function completeTodo(index){ return { type:COMPLETE_TODO, index } }function selectFilter(filter){ return { type:SETFILTER, filter } }var initState = { filter:'SHOW_ALL', todos:[] }function todos(state = [], action) { switch (action.type) { case ADD_TODO: return [...state, { text: action.text, completed: false }]; case COMPLETE_TODO: return [ ...state.slice(0, parseInt(action.index)), Object.assign({}, state[action.index], { completed: true }), ...state.slice(parseInt(action.index)+ 1) ]; default: return state; } }function setFilter(state = FILTER.SHOW_ALL,action){ switch(action.type){ case SETFILTER: return action.filter; default: return state; } }var todoApp = combineReducers({ filter:setFilter, todos:todos });var store = createStore(todoApp);var unsubscribe = store.subscribe(()=>{ console.log(store.getState()); });console.log('新增吃飯'); store.dispatch(addTodo('吃飯'));console.log('新增睡覺'); store.dispatch(addTodo('睡覺'));console.log('完成吃飯'); store.dispatch(completeTodo(0));console.log('新增打豆豆'); store.dispatch(addTodo('打豆豆'));console.log('完成睡覺'); store.dispatch(completeTodo(0));console.log('setFilter'); store.dispatch(selectFilter(FILTER.SHOW_COMPLETE)); unsubscribe();
小結
Action 使用者發起一個動作請求的請求內容
State 儲存應用現有的狀態
Reducer 根據 Action 請求內容的 Type 欄位去匹配要進行的動作與修改的狀態
Store 儲存庫,把 Reducer 傳入 createStore 的構造器中得到,只有透過它的 dispatch 方法傳入一個 Action 請求內容,之後自動去 Reducer 中匹配 Type 欄位,之後去修改相應的狀態
作者:Nodelover
連結:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2325/viewspace-2811829/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- react之redux狀態管理ReactRedux
- 都8102年了!是時候有個新的狀態容器取代redux了!Redux
- 前端狀態管理框架之Redux前端框架Redux
- React 快速上手 - 08 redux 狀態管理 react-reduxReactRedux
- Flutter 狀態管理之 Scoped Model & ReduxFlutterRedux
- Flutter | 狀態管理探索篇——Redux(二)FlutterRedux
- 基於 Redux + Redux Persist 進行狀態管理的 Flutter 應用示例ReduxFlutter
- Docker 容器的健康狀態檢查Docker
- Flutter 狀態管理之 Redux,BLoC,Provider 的流程分析FlutterReduxBloCIDE
- JavaScript狀態資料JavaScript
- React資料狀態管理 --- Redux,Redux-Saga以及進階DvaReactRedux
- Flutter狀態管理學習手冊(二)——ReduxFlutterRedux
- 從 Redux 說起,到手寫,再到狀態管理Redux
- Redux複雜應用(一):淺談狀態管理Redux
- [譯]開發類 redux 庫來理解狀態管理Redux
- Docker容器的退出狀態碼及解決方法Docker
- 基於Redux/Vuex/MobX等庫的通用化狀態OOPReduxVueOOP
- 借鑑redux,實現一個react狀態管理方案ReduxReact
- 如何直觀的在JavaScript中管理狀態JavaScript
- 你再也不用使用 Redux、Mobx、Flux 等狀態管理了Redux
- Snyk: 2019年JavaScript 框架的狀態安全報告JavaScript框架
- 從React Redux的實際業務場景來看有限狀態機ReactRedux
- Next.js踩坑入門系列(五)— 引入狀態管理reduxJSRedux
- [ - Flutter 狀態篇 redux - ] StoreConnector還是StoreBuilder,讓distinct把好關FlutterReduxRebuild
- Next App Router 模式下,如何同步服務端 Redux 初始狀態?APP模式服務端Redux
- 原生 JavaScript 實現 state 狀態管理系統JavaScript
- Redux 包教包會(二):引入 combineReducers 拆分和組合狀態邏輯Redux
- 一個帶有Redux狀態管理的本機元件(計數器)的Github專案Redux元件Github
- 一個好用的檢視Angular應用ngrx狀態的Chrome擴充套件:Redux devToolsAngularChrome套件Reduxdev
- Flutter入門與實戰(五十八): 看 Flutter 如何分享 React 的 Redux狀態管理FlutterReactRedux
- [譯] 使用原生 JavaScript 構建狀態管理系統JavaScript
- 2020 年 JavaScript 狀態調研報告小結JavaScript
- Flutter實踐:深入 Flutter 的狀態管理方式(3)——旅途小結與Redux實踐FlutterRedux
- duxapp放棄了redux,在duxapp中區域性、全域性狀態的實現方案APPRedux
- C++容器巢狀實現動態二維陣列C++巢狀陣列
- 【docker專欄6】詳解docker容器狀態轉換管理命令Docker
- 淺談前端的狀態管理,以及anguar的狀態管理庫前端
- Redux/Mobx/Akita/Vuex對比 - 選擇更適合低程式碼場景的狀態管理方案ReduxVue