Redux的基本使用過程步驟詳解
Redux的使用過程
Redux測試項目的搭建
1.創(chuàng)建一個新的項目文件夾:learn-redux
# 執(zhí)行初始化操作
npm init -y
或yarn init -y
# 安裝redux:
npm install redux --save
或yarn add redux
2.創(chuàng)建src目錄,在src目錄下創(chuàng)建一個store文件夾, 并且在該文件夾下創(chuàng)建index.js文件
3.可以修改package.json用于執(zhí)行index.js, 也可以不配置, 直接使用node命令運(yùn)行
"scripts": { "start": "node src/index.js" }
Redux的基本使用步驟
1.創(chuàng)建一個對象,作為我們要保存的狀態(tài)state:
// 由于測試項目在node環(huán)境下, 因此使用require方式導(dǎo)入 const { createStore } = require("redux") // 創(chuàng)建的要存儲的state: initialState const initialState = { name: "chenyq", age: 18 }
2.創(chuàng)建Store來存儲這個state
由于創(chuàng)建的state是不能直接放到創(chuàng)建的store中的, 需要通過reducer將數(shù)據(jù)添加到store中, 因此創(chuàng)建store時必須創(chuàng)建reducer;
reducer函數(shù)的返回值, 會作為store之后存儲的state
// 定義reducer, 將要存儲的state作為返回值返回 function reducer() { return initialState } // 創(chuàng)建的store, 內(nèi)部會自動回調(diào)reducer, 拿到initialState const store = createStore(reducer) // 導(dǎo)出store module.exports = store
我們可以在其他文件中通過
store.getState
來獲取當(dāng)前的state;
// 導(dǎo)入創(chuàng)建的store const store = require("./store") // 獲取store中的state console.log(store.getState())
3.通過action來修改state
錯誤演示
: 直接修改store
store.getState().name = "abc"
修改store中的數(shù)據(jù)不能直接修改, 必須要通過dispatch來派發(fā)action;
通常action中都會有type屬性,也可以攜帶其他的數(shù)據(jù);
// 定義一個action const nameAction = { type: "change_name", name: "abc" } // 派發(fā)action store.dispatch(nameAction)
當(dāng)然上面代碼中, 也可以寫為一行
// 派發(fā)action store.dispatch({ type: "change_name", name: "abc" })
4.修改reducer中的處理代碼
reducer接收兩個參數(shù):
參數(shù)一: store中當(dāng)前保存的state
參數(shù)二: 本次需要更新的action
只要調(diào)用dispatch就會重新執(zhí)行reducer函數(shù)
這里一定要記住,reducer是一個純函數(shù),不可以直接修改state, 后面我會講到直接修改state帶來的問題;
// 第一次state是undefined, 因此給一個默認(rèn)值將初始化數(shù)據(jù)添加到store中 function reducer(state = initialState, action) { // 有數(shù)據(jù)更新時, 返回一個新的state if (action.type === "change_name") { return { ...state, name: action.name } } // 沒有數(shù)據(jù)更新時, 返回之前的state return state }
5.可以在派發(fā)action之前,監(jiān)聽store的變化:
通過
store.subscribe()
函數(shù)可以監(jiān)聽store中的數(shù)據(jù)變化
store.subscribe()
函數(shù)的參數(shù)接收一個函數(shù), 該函數(shù)在store數(shù)據(jù)發(fā)生更新自動回調(diào)
const store = require("./store") // 例如: 監(jiān)聽數(shù)據(jù)的變化, 當(dāng)store變化, 就獲取最新的state store.subscribe(() => { console.log(store.getState()) }) store.dispatch({ type: "change_name", name: "abc" }) store.dispatch({ type: "change_name", name: "aaa" })
6.封裝函數(shù)動態(tài)生成action
例如上面代碼中, 我們修改名稱多次, 只有傳入的action的name屬性值不相同, 那么我們可以封裝一個函數(shù), 動態(tài)的生成action, 這也是開發(fā)中一貫的做法
// 創(chuàng)建修改name的action const changeNameAction = (name) => ({ type: "change_name", name }) // 創(chuàng)建修改age的action const changeAgeAction = (num) => ({ type: "change_age", num }) // 在派發(fā)action時, 我們就可以調(diào)用函數(shù)即可獲取action store.dispatch(changeNameAction("aaa")) store.dispatch(changeNameAction("bbb")) store.dispatch(changeNameAction("ccc")) store.dispatch(changeAgeAction(10)) store.dispatch(changeAgeAction(20)) store.dispatch(changeAgeAction(30)) store.dispatch(changeAgeAction(40))
Redux目錄的結(jié)構(gòu)劃分
如果我們將所有的邏輯代碼寫到一起,那么當(dāng)redux變得復(fù)雜時代碼就難以維護(hù)。
例如上面代碼中, 我們封裝的動態(tài)創(chuàng)建action的函數(shù), 這種動態(tài)生成action的函數(shù)在項目中可能會有很多個, 而且在其他多個文件中也可能會使用, 所以我們最好是有一個單獨(dú)的文件夾存放這些動態(tài)獲取action的函數(shù)
接下來,我會對代碼進(jìn)行拆分,將store、reducer、action、constants拆分成一個個文件。
創(chuàng)建store/index.js文件: index文件中, 我們只需要創(chuàng)建store即可
const { createStore } = require("redux") // 引入reducer const reducer = require("./reducer") // 創(chuàng)建的store, 內(nèi)部會自動回調(diào)reducer, 拿到initialState const store = createStore(reducer) // 導(dǎo)出store module.exports = store
創(chuàng)建store/reducer.js文件: 在真實項目中, reducer這個函數(shù)我們會越寫越復(fù)雜, 造成我們index.js文件越來越大, 所以我們將reducer也抽離到一個單獨(dú)的文件中
const { CHANGE_NAME, CHANGE_AGE } = require("./constants") // 創(chuàng)建的要存儲的初始化state const initialState = { name: "chenyq", age: 18 } // 定義reducer, 將要存儲的state作為返回值返回 // 第一次state是undefined, 因此給一個默認(rèn)值將初始化數(shù)據(jù)添加到store中 function reducer(state = initialState, action) { switch(action.type) { case CHANGE_NAME: return { ...state, name: action.name } case CHANGE_AGE: return {...state, age: state.age + action.num} } // 沒有數(shù)據(jù)更新時, 返回之前的state return state } module.exports = reducer
創(chuàng)建store/constants.js文件: 將type的類型定義為常量(防止寫錯的情況), 這些常量最好也防止一個單獨(dú)的文件中
// store/constants.js const CHANGE_NAME = "change_name" const CHANGE_AGE = "change_age" module.exports = { CHANGE_NAME, CHANGE_AGE }
創(chuàng)建store/actionCreators.js文件: 將封裝的動態(tài)創(chuàng)建action的函數(shù)放在該文件中, 在需要使用的地方導(dǎo)入即可
const { CHANGE_NAME, CHANGE_AGE } = require("./store/constants") // 創(chuàng)建修改name的action const changeNameAction = (name) => ({ type: CHANGE_NAME, name }) // 創(chuàng)建修改age的action const changeAgeAction = (num) => ({ type: CHANGE_AGE, num }) module.exports = { changeNameAction, changeAgeAction }
最終形成如下目錄結(jié)構(gòu), 這也是官方推薦的目錄結(jié)構(gòu), 一個store中包含這四個文件夾
注意:node中對ES6模塊化的支持, 建議使用CommonJS規(guī)范
React的三大原則
單一數(shù)據(jù)源
整個應(yīng)用程序的state被存儲在一顆object tree中,并且這個object tree只存儲在一個 store 中:
Redux并沒有強(qiáng)制讓我們不能創(chuàng)建多個Store,但是那樣做并不利于數(shù)據(jù)的維護(hù);
單一的數(shù)據(jù)源可以讓整個應(yīng)用程序的state變得方便維護(hù)、追蹤、修改;
State是只讀的
唯一修改State的方法一定是觸發(fā)action,不要試圖在其他地方通過任何的方式來修改State:
這樣就確保了View或網(wǎng)絡(luò)請求都不能直接修改state,它們只能通過action來描述自己想要如何修改state;
這樣可以保證所有的修改都被集中化處理,并且按照嚴(yán)格的順序來執(zhí)行,所以不需要擔(dān)心race condition(竟態(tài))的問題;
使用純函數(shù)來執(zhí)行修改
通過reducer將舊state和actions聯(lián)系在一起,并且返回一個新的State:
隨著應(yīng)用程序的復(fù)雜度增加,我們可以將reducer拆分成多個小的reducers,分別操作不同state tree的一部分;
但是所有的reducer都應(yīng)該是純函數(shù),不能產(chǎn)生任何的副作用;
到此這篇關(guān)于Redux的基本使用過程詳解的文章就介紹到這了,更多相關(guān)Redux基本使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
javascript發(fā)送短信驗證碼實現(xiàn)代碼
我們在注冊賬號,或者是參加活動時,都會向手機(jī)發(fā)送收短信驗證碼,短信驗證碼到底是如何實現(xiàn)的,本文為大家揭曉,并為大家分項1javascript發(fā)送短信驗證碼實現(xiàn)代碼,感興趣的小伙伴們可以參考一下2015-11-11JavaScript實現(xiàn)標(biāo)題欄文字輪播效果代碼
這篇文章主要介紹了JavaScript實現(xiàn)標(biāo)題欄文字輪播效果代碼,涉及JavaScript基于時間函數(shù)及流程控制操作標(biāo)題欄文字的相關(guān)技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-10-10JavaScript常用數(shù)組操作方法,包含ES6方法
這篇文章主要介紹了JavaScript常用數(shù)組操作方法,包含ES6方法,本文分步驟給大家介紹的非常詳細(xì),具有一定的參考借鑒借鑒價值,需要的朋友可以參考下2018-09-09JavaScript擴(kuò)展運(yùn)算符的學(xué)習(xí)及應(yīng)用詳情(ES6)
這篇文章主要介紹了JavaScript擴(kuò)展運(yùn)算符的學(xué)習(xí)及應(yīng)用詳情(ES6),擴(kuò)展運(yùn)算符是ES6新增的一種運(yùn)算符,他可以幫助我們簡化代碼,簡化操作,具體相關(guān)知識感興趣的小伙伴可以查看下面文章的簡單介紹2022-08-08