接續上一篇我們成功地建立了一個 Redux 的完整程序於 index.js 之中,那這一篇就來分享常用的分層概念,首先我們先回到這張圖上。
讓我們按著這個圖表將 index.js 裡面的檔案做一下分類,然後分別另開三個資料夾為store, action, reducer,接著我們一樣先來處理 action 的部分,首先我們先把本來在定義 COFFEE_ORDERED 的部分用一個 js 檔案去做分離,並建立於action資料夾下,如以下:
// 我的範例上是簡單採types.js來命名,但當檔案多時通常還會再次拆分
const COFFEE_ORDERED = 'COFFEE_ORDERED';
// 這裡採node的方式做export/import
module.exports = {
COFFEE_ORDERED,
};
這次我們嘗試分離 action 的部分,一樣建立在 action 資料夾下:
const { COFFEE_ORDERED } = require("./types")
// 建立Action
const orderCoffee = () => {
return {
type: COFFEE_ORDERED,
payload: 1
}
}
// 除上述function的方法以外也可以直接帶入object
const orderCoffeeObj = {
type: COFFEE_ORDERED,
payload: 1
}
// 但是我個人是不推薦這樣的做法,透過function還可以帶參數來設定,如下
const orderCoffeeByNum = (num) => {
return {
type: COFFEE_ORDERED,
payload: num
}
}
module.exports = {
orderCoffee,
orderCoffeeByNum,
orderCoffeeObj
}
新建檔案後,再回到 index.js 裏面調整引入的部分:
const { orderCoffee, orderCoffeeObj, orderCoffeeByNum } = require('./action/order');
接著我們繼續來調整 reducer 的段落,在整理之前需要先講解一下,通常一個專案會有好多個 reducer 來實現多種不同的功能,所以在整併時通常會多一層來讓我們好分辨到底是哪個 reducer 和控制了哪些工能。
於是我們於 reducer 的資料夾下新建一個 orderReducer.js 的檔案,將我們之前寫好的段落移植過來:
// orderReducer.js
const { COFFEE_ORDERED } = require("../action/types");
const initialState = {
numOfCoffee: 20,
numOfCoffeeBean: 20,
numOfCake: 20,
}
// 這部分和useReducer hook是一樣的
const orderReducer = (state = initialState, action) => {
switch(action.type) {
case COFFEE_ORDERED:
return {
...state,
numOfCoffee: state.numOfCoffee - action.payload
}
default:
return state;
}
}
module.exports = { orderReducer }
完成後,我們在同路徑下新增一個 index.js 的檔案,並使用 redux 的 combineReducers function 來整合所有定義好的 reducer 檔案,如下:
// reducer/index.js
const { combineReducers } = require("redux");
const { orderReducer } = require('./orderReducer')
const reducers = combineReducers({
orderReducer,
})
module.exports = {
reducers
}
最後,我們來處理 store,這邊就比較單純一點了,我們一樣 CD 到 store 的資料夾下並新增 index.js 檔案,將原本在 ./index.js 的段落搬遷過來,如下:
// store/index.js
const { createStore } = require("redux");
const { reducers } = require("../reducer");
const store = createStore(reducers)
module.exports = {
store,
}
做完以後將原本 ./index.js 重複的段落刪除後會得以下結果:
// 從剛才拆出來的地方引入
const { orderCoffee, orderCoffeeObj, orderCoffeeByNum } = require('./action/order');
const { store } = require('./store');
// 來試試拿取 initialState
console.log('initial state', store.getState());
// 當state change時可以觸發的 callback
const unsubscribe = store.subscribe(() => console.log('更新', store.getState()))
// 讓我們來試看看點餐
store.dispatch(orderCoffee())
store.dispatch(orderCoffeeObj)
store.dispatch(orderCoffeeByNum(2))
unsubscribe()
這時候可以測試看看結果,應該會如以下:
initial state {
orderReducer: { numOfCoffee: 20, numOfCoffeeBean: 20, numOfCake: 20 }
}
更新 {
orderReducer: { numOfCoffee: 19, numOfCoffeeBean: 20, numOfCake: 20 }
}
更新 {
orderReducer: { numOfCoffee: 18, numOfCoffeeBean: 20, numOfCake: 20 }
}
更新 {
orderReducer: { numOfCoffee: 16, numOfCoffeeBean: 20, numOfCake: 20 }
}
這時候會發現 state 多了一個 key 為 orderReducer,承上所述,為了能夠整合許多不同 reducer 所以利用了combineReducers 的回傳結果就是如此。
那麼今天的內容就到這裡,下一篇我們來擴充一些複雜一點的功能吧!