摘要:只要輸入的值不變,每次輸出都是一樣的值。指定位置元素運算操作如可用以下方式代替主要是生成中最核心的對象。描述發生了什么,是響應并對進行更新。生成的對象包含個方法,分別為,和。按照約定,具有字段來表示它的類型。
前言:redux基礎用法 1. Action
一開始接觸redux的時候最令我記住的一句話是:You Might Not Need Redux(那我還寫這篇文章干嘛?手動滑稽)
回歸正題,本文主要是圍繞redux的作者Dan的視頻,由淺入深了解redux
如果需要改變state(狀態),我們需要使用到Action。Action是一個普通的JavaScript對象描述state變化。action的屬性可以自定義,但是必須有一個叫type的屬性,值是string類型(方便序列化)。每一個action都是對state的一個(minimal change)最小修改,在應用里什么東西發生了變化。
//創建一個加法器,減法器 const INCREMENT = "INCREMENT"; { type: INCREMENT } const DECREMENT = "DECREMENT"; { type: DECREMENT } //----------------------------- //比如添加新todo任務 // action type字符常量 const ADD_TODO = "ADD_TODO"; // ADD_TODO action { type: ADD_TODO, text: "Learn Redux" }2. 純函數和非純函數
什么是純函數?
純函數就是沒有副作用的函數,不包含數據庫查詢、網絡請求等操作。只要輸入的值不變,每次輸出都是一樣的值。
//pure function function square(x) { return x * x; } // Impure function function square(x) { updateXInDatabase(x); return x * x; }
為什么需要說純函數?
因為在redux中,有些函數必須是純函數,比如reducer,所以在編碼的時候有必要注意。
注意!reducer必須是純函數,不能更改state,每次都必須返回一個新的state。
reducer,其實就是描述舊狀態(previous state)如何轉換為當前狀態(current state)的函數。
這里使用的是計數器例子,我們通過action的type
const counter = (state = 0, action) => { switch (action.type) { case "INCREMENT": return state + 1; case "DECREMENT": return state - 1; default: return state; } }
reducer是需要固定的形式的,需要傳入2個參數,一個是state,另一個是action。
我們這里先不要管為什么要這么寫,記住這是redux的規定即可。我們可以通過es6的默認參數方式賦予state初始默認值。
因為reducer是純函數,因此需要注意幾點:
不能改變參數
不能使用非純函數
接下來我們一起看一下怎么處理reducer中對數據的處理。
reducer的state處理通常是兩種數據類型:
Object
Array
Object// 注意,不能直接改變state中的屬性值 state.name = "ken" // ?這種對name屬性賦值操作是不允許的 // --------------------------- // 正確??做法 // 1,使用Object的assign方法,需要對瀏覽器做polyfill return Object.assign({}, state, { name: "ken" }); // 或者使用es7的解構方法 return { ...state, name: "ken", };Array
array的操作中,常用操作為:
增(push)
刪(splice)
指定位置元素運算操作,如 array[index]++ array[index] = array[index] * 2等操作
注意上述3個操作都是會改變原數組,因此需要使用“純”操作代替這些“非純”操作。
push/pop/shift/unshift
如果需要使用push,我們可以使用concat方法代替。
concat方法返回一個新數組,且不改變原數組。
array.push(x); // ? array.concat(x); // ? // 或者使用解構方式 [...array, x];
splice
同理,splice操作也是會改變原數組,我們可以用slice去代替。
array.splice(index, 1); // ? [...array.slice(0, index), ...array.slice(index + 1)]; // ?
指定位置元素運算操作
// 如 array[index]++ // ? // 可用以下方式代替 ? [...array.slice(0, index), array[index] + 1, ...array.slice(index + 1)];5. createStore
createStore主要是生成redux中最核心的Store對象。action描述“發生了什么”,reducer是響應action并對state進行更新。而store可以看成把action和reducer聯系起來的一個對象。
import { createStore } from redux; const store = createStore(counter) console.log(store.getState()); // output 0 store.dispatch({ type: "INCREMENT"} ); console.log(store.getState()); // output 1 // ------------------------------ const render = () => { document.body.innerText = store.getState(); }; store.subscribe(render); document.addEventListener("click", () => { store.dispatch({ type: "INCREMENT" }); });
createStore生成的store對象包含3個方法,分別為getState,dispatch和subscribe。其中subscribe函數的返回值是一個函數,用于取消訂閱。
getState()返回應用當前的state樹。
dispatch(action)分發action。這個是觸發state改變的唯一方法。
action是描述應用變化的普通對象。按照約定,action 具有 type 字段來表示它的類型。type 也可被定義為常量或者是從其它模塊引入。
subscribe(listener)添加一個變化監聽器。listener是一個函數,每當執行dispatch方法時候就會執行listener。 在例子中,每次dispatch一個action,就會觸發render函數執行。如果需要解除綁定監聽,執行subscribe返回的函數即可。
6. 實現一個簡單版的createStore我們知道createStore返回的是一個store對象,其中包括getState,dispatch和subscribe方法。
當然接下來的實現是最簡單的實現,去掉了很多參數校驗、store enhancer(即中間件)和類RxJS等reactive庫支持。有興趣更深了解的同學可以看看redux的createStore源碼(ps:我打算下一篇文章寫關于redux源碼??)
const CreateStore = (reducers, initState = {}) { let currentState = initState; let listeners = []; // getState就是簡單的把當前的state返回給調用者 const getState = () => currrentState; // subscribe: // 如果對觀察者模式(發布-訂閱模式)比較熟悉的同學就會發現,這其實就是做訂閱 // const subscribe = listener => { listeners.push(listener); return function unsubscribe() { listeners = listeners.filter(currentListener => currentListener !== listener) }; }; // 同理,這個是觀察者模式中的發布 // 接收到action后,通過reducer更新state,并且把listeners執行一遍 const dispatch = action => { reducers(currentState, action); listens.forEach(listener => listener()); } // 初始化 // 讓reducers返回他們的初始state dispatch({}); return { getState, subscribe, dispatch, }; };
我們很簡單就實現了createStore,當然實際上還是會稍微復雜一點。
7. combineReducers從上述我們實現的createStore源碼可以看出,傳入的reducer只有一個。
真實的應用中reducer是多個的,因此我們需要把reducer組合起來。combineReducers就是幫我們完成這個任務。
import { combineReducers } from "redux"; const todosReducer = (state = {}, action) => { switch (action.type) { ... } }; const visibilityFilterReducer = (state = {}, action) => { switch (action.type) { ... } }; const reducer = combineReducers({ todos: todosReducer, visibilityFilter: visibilityFilterReducer, }); const store = createStore(reducer, {});
代碼主要完成了把todosReducer和visibilityFilterReducer合并為一個reducer;todos和visibilityFilter分別是兩個變量接收兩個reducer處理的結果。
其實我們可以這么理解
const todosAndVisibilityFilterReducer = (state = { todos: {}, visibilityFilter: {} }, action) => { switch (action.type) { ... // 合并todosReducer和visibilityFilterReducer的case即可 } } const store = createStore(todosAndVisibilityFilterReducer, {});
當然真實項目不能這么搞,既然redux提供了combineReducers,我們就應該使用。
8. 實現一個簡單版的combineReducers和createStore一樣,我們寫一個簡單版本的combineReducers。
//可以理解combineReducers就是一個reducer,因此其返回值是一個可以傳入(state, action)的函數 const combineReducers = (reducers = {}) => { return (state = {}, action) => { // 和普通的reducer一樣,返回一個新的state作為返回值 // 此處選擇Array.reducer方法更加簡潔;forEach還要創建一個臨時變量保存新值。 return Object.keys(reducers).reduce((nextState, key) => { // 這里的key可以套入todos/visibilityFilter // 執行每個reducer方法,并取得其返回的state值,放入nextState中 nextState[key] = reducers[key](state[key], action); return nextState; }); } };參考
redux官網
Dan的Getting Started With Redux系列課程(非常贊,5星級推薦)
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/98720.html
摘要:資料合集學習有段時間了,相關不錯的資料整理下,希望能幫到有緣人五顆星推薦中文文檔通讀不下邊,翻譯的很好,想理解清楚,定下心來,認真讀,必有收獲官方推薦資料合集,沒有啥說的中間件深入淺出就因為看了這篇文章才更加深入學習,同時對有了別樣的看法 redux 資料合集 學習redux有段時間了,相關不錯的資料整理下,希望能幫到有緣人 五顆星推薦 中文文檔 通讀不下3邊,翻譯的很好,想理解清楚...
摘要:另外,內置的函數在經過一系列校驗后,觸發,之后被更改,之后依次調用監聽,完成整個狀態樹的更新。總而言之,遵守這套規范并不是強制性的,但是項目一旦稍微復雜一些,這樣做的好處就可以充分彰顯出來。 這一篇是接上一篇react進階漫談的第二篇,這一篇主要分析redux的思想和應用,同樣參考了網絡上的大量資料,但代碼同樣都是自己嘗試實踐所得,在這里分享出來,僅供一起學習(上一篇地址:個人博客/s...
摘要:另外,內置的函數在經過一系列校驗后,觸發,之后被更改,之后依次調用監聽,完成整個狀態樹的更新??偠灾?,遵守這套規范并不是強制性的,但是項目一旦稍微復雜一些,這樣做的好處就可以充分彰顯出來。 這一篇是接上一篇react進階漫談的第二篇,這一篇主要分析redux的思想和應用,同樣參考了網絡上的大量資料,但代碼同樣都是自己嘗試實踐所得,在這里分享出來,僅供一起學習(上一篇地址:個人博客/s...
摘要:謹記,請勿犯這樣的錯誤。由于在之前的教程中,積累了堅實的基礎。其實,這是有緣由的其復雜度在早期的學習過程中,將會帶來災難性的影響。該如何應對對于來說,雖然有大量的學習計劃需要采取,且有大量的東西需要學習。 前言倘若你正在建造一間房子,那么為了能快點完成,你是否會跳過建造過程中的部分步驟?如在具體建設前先鋪設好部分石頭?或直接在一塊裸露的土地上先建立起墻面? 又假如你是在堆砌一個結婚蛋糕...
閱讀 1617·2021-11-22 14:45
閱讀 1063·2021-11-17 09:33
閱讀 3322·2021-09-02 09:48
閱讀 970·2019-08-30 15:54
閱讀 2767·2019-08-30 15:53
閱讀 2553·2019-08-30 12:54
閱讀 2241·2019-08-29 12:37
閱讀 2421·2019-08-26 13:58