iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 17
1
Modern Web

三十天路邊賭場上線了!系列 第 17

DAY17 導入狀態管理、造個Redux

  • 分享至 

  • xImage
  •  

前言

今天不刻介面,今天來導入我們的狀態管理,管理我們未來會遇到的奇形怪狀的狀態!我本來想說直接引入Redux,因為Redux並不是React專用,但後來發現我們使用typescript,好像定義檔只有react-redux才有,我又不想花很多時間在寫定義檔,原因是我對撰寫定義檔並不熟悉呵呵。補充:Redux是Typescript寫的,可以直接拿來用就好,當下沒注意到寫完才發現。

總而言之,我其實可以寫一個事件觸發器直接當作類似Redux的結構進行更新,但考慮很久我還是直接寫一個Redux就好了,因為我印象中簡易版本Redux並不會特別複雜。

臨摹

一搬我們在使用Redux的時候簡易樣子大會是這樣。
透過CreateStore建出一個封裝好的Store,我們可以對Store取狀態,但要修改狀態必須透過dispatch派發。

import { createStore } from 'redux';

const store = createStore()
const state = store.getState()

store.dispatch('xxxx')

於是我們開始打造吧!

以下就是大致上我們基本的樣子,透過createStore把我們的Reducer包裝至我們dispatch內,這樣我們派發後,Store會幫我們把State經過我們的Reducer產生出我們要的變化,並把舊的State取代。

我們可以透過getState()取得新的狀態

export function createStore(initialReducer: Function, initalState = {}): Store {
  let reducer = initialReducer
  let state = reducer(initalState, { type: '__INIT__' })
  return {
    getState() {
      return state
    },
    dispatch(action: Action): void {
      state = reducer(state, action)
    }
  }
}

訂閱

再來是因為我們要取得新的狀態,其他組件並不知道我們目前的狀態更新了,因此需要Observer的概念,讓組件監聽著我們的Store。

其實就很像是EventEmitter那種的觸發器而已,相當容易理解,我覺得比較精巧的部分是,他返回一個function可以直接unSubscribe這點讓我滿驚訝的,我從來沒想過可以這樣寫,學到了一課!

export function createStore(initialReducer: Function, initalState = {}): Store {
  let reducer = initialReducer
  let subscribes: Array<Function> = []
  let state = reducer(initalState, { type: '__INIT__' })
  return {
    getState() {
      return state
    },
    dispatch(action: Action): void {
      state = reducer(state, action)
      subscribes.forEach(subscriber => subscriber())
    },
    subscribe(listener: Function): Function {
      subscribes.push(listener)
      return () => {
        subscribes = subscribes.filter(subscriber => subscriber !== listener)
      }
    }
  }
}

StoreEnhancer

我其實已經不知道這怎麼翻譯的,我這是看參考文章及參考Redux原碼的。

這是指我們在createStore可傳入enhancer用來很像是middleware的概念,但其實Redux有另外一套middleware的方法,讓我們有機會可以在變化前後縞一些事,像是log資料等等。

export function createStore(initialReducer: Function, initalState = {}, enhancer?: Function): Store {
  if (enhancer) {
    return enhancer(createStore)(initialReducer, initalState)
  }
  let reducer = initialReducer
  let subscribes: Array<Function> = []
  let state = reducer(initalState, { type: '__INIT__' })
  return {
    getState() {
      return state
    },
    dispatch(action: Action): void {
      state = reducer(state, action)
      subscribes.forEach(subscriber => subscriber())
    },
    subscribe(listener: Function): Function {
      subscribes.push(listener)
      return () => {
        subscribes = subscribes.filter(subscriber => subscriber !== listener)
      }
    },
    replaceReducer(newReducer: Function): void {
      reducer = newReducer
      this.dispatch({ type: '__REPLACE__' })
    }
  }
}

enhancer的使用大概是以下這樣使用。

let enhancer = () => {
  return createStore => (reducer, initialState, enhancer) => {
    const store = createStore(reducer, initialState)
    function dispatch(action) {
      const res = store.dispatch(action);
      const newState = store.getState();
      return res;
    }
    return {...store, dispatch}
  }
}
let store = createStore(reducer, {}, enhancer)
store.getState()
store.dispatch('xxx')

整合

接下來我們新增到我們專案吧!在非常下面的小地方!redux.js就是redux核心檔案,store是我們在新增的有的沒的。

└─src
    │  App.ts
    │  Game.ts
    │  
    ├─components
    │  ├─elements
    │  │      Animation.ts
    │  │      Sprite.ts
    │  │      Texture.ts
    │  │      Wrapper.ts
    │  │      WrapperContainer.ts
    │  │      WrapperContainerCenter.ts
    │  │      WrapperType.ts
    │  │      
    │  ├─groups
    │  │      Body.ts
    │  │      Casino.ts
    │  │      ChipBox.ts
    │  │      Loading.ts
    │  │      Navbottom.ts
    │  │      Navtop.ts
    │  │      Pokers.ts
    │  │      Table.ts
    │  │      
    │  └─objects
    │          AreaBetNumber.ts
    │          Bg.ts
    │          Chip.ts
    │          Countdown.ts
    │          CountdownNumber.ts
    │          Dealer.ts
    │          Desk.ts
    │          DeskHover.ts
    │          Info.ts
    │          InfoMoneyNumber.ts
    │          Poker.ts
    │          PokerPoint.ts
    │          PokerWin.ts
    │          TotalBetNumber.ts
    │          WaitNextBetNotify.ts
    │          
    ├─config
    │      chipType.ts
    │      imagePath.ts
    │      loadingPath.ts
    │      pokerPoint.ts
    │      pokerType.ts
    │      
    ├─loaders
    │      Loader.ts
    │      
    ├─store
    │      redux.ts ***
    │      store.ts ***
    │      
    └─utils
            tools.ts
            

store裡面我們就新增我們的reducer,這邊我們單一用一個store就好了,所有東西都放在這裡面就好,為什麼呢?因為我其實對redux掌握度不夠高,我記得可以多個合併,但我很久沒有摸了。未來還是想回到React的懷抱,之後再來全面進攻R的世界。

底下還要初始化我們的狀態哦!

store.js

function reducer(state: any, action: Action) {
  if (action.type === 'UPDATE_CHOOSE_CHIP') return Object.assign(state, { chip: action.payload.chip });
  if (action.type === 'UPDATE_USER_BALANCE') return Object.assign(state, { balance: action.payload.balance });
  return state
}

const store = createStore(reducer, {
  chip: '1000',
  balance: 0
})

連結

Github
Redux in 27 lines
Redux Source


上一篇
DAY16 撲克牌開牌、顯示點數
下一篇
DAY18 狀態管理初始化、籌碼金額使用Redux
系列文
三十天路邊賭場上線了!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言