sujingjhong.com


JS / 為什麼不把 Redux type 設定成 Symbol 呢?

為什麼不把 Redux Type 設定成 Symbol 呢? #

前端有用 Redux 的工程師都知道,用 Redux 如果需要改變狀態,需要發送行為到 store 裡去,我們常常會寫類似下面的工廠函數:

function someAciton(todo){
  return {
    type: "SOME_ACTION",
    payload: todo
  };
}

接下來為了避免 type 有重複問題,會另外建立一個 ActionTypes 清單,裡面會長的類似:

export const ACTION_A = 'ACTION_A';
export const ACTION_B = 'ACTION_B';
export const GOD_DAMN_ACTION = 'GOD_DAMN_ACTION';
...

這時候如果有 100 個 action 你就需要建立 100個 ActionType。OK, fine.

於是我就想到,既然都要建那麼多個了,有什麼可以比較省事的方法呢?

我就想到 SymbolSymbolES6 引進的,每個 Symbol 都是獨一無二,就算是同一個 Symbol('I_AM_A_SYMBOL') 和另外一個 Symbol('I_AM_A_SYMBOL') ,即使傳入的值一樣,他還是獨一無二。

所以用在上述情境就變成:

export const ACTION_A = Symbol('');
export const ACTION_B = Symbol('');
export const GOD_DAMN_ACTION = Symbol('');
...

在動作函數就可以:

import { ACTION_A } from './ActionTypes.js'

function someAciton(todo){
  return {
    type: ACTION_A,
    payload: todo
  };
}

看起來好像很棒?

但如果這方法那麼棒,怎 Redux 一開始沒用這個呢?但他還真的有用過:

Redux#4 裡面,作者 gaearon 還曾經那麼使用過,不過他說他後來發現一個問題

I thought of that, but this kind of screws the replay thing. (AFAIK you can't serialize and then deserialize symbols.) I want to pass them around for devtools, localStorage persistence, etc.

接著他更進一步說明

You can't take an array of actions that use symbols, serialise them to JSON, save to localStorage, and later deserialise and replay them in a different browser session.

簡單來說就是不能做 SerDes。複雜一點就是你不能把一大堆動作轉存成陣列,轉為 JSON 存起來,丟到另一個瀏覽器環境,再把它轉換回來。

雖然說技術上應該是可行的,準備一個 Objecttype 還有 Symbol 互相映射。或者一開始就將 ActionTypes 改寫成:

export default {
  ACTION_A: Symbol(''),
  ACTION_B: Symbol(''),
  ACTION_C: Symbol(''),
};

不過這樣產生另一個問題:只有開發者才知道要怎麼映射。如果要用第三方工具,例如 redux-devtools-extension,其他開發者根本不知道你的 type 要怎麼映射,而根本無法銜接。

再來就算建立好映射表了,在 Console 上要好好的辨識 Symbol 話,就也要好好取名,例如:

export const ACTION_A = Symbol('');
export const ACTION_B = Symbol('');

ACTION_AACTION_BConsole 上都是顯示 Symbol()。很好,那我們加一些辨識字元:

export const ACTION_A = Symbol('ACTION_A');
export const ACTION_B = Symbol('ACTION_B');

很好,現在在 Console 上就會顯示 Symbol(ACTION_A)Symbol(ACTION_B)

那和一開始的比較起來,似乎發現了點問題:這樣根本是多此一舉

我目前唯一想到可以用的情境,就是 ActionType 已經和其他人撞名了!不過在現代瀏覽器如果有實現 ES6 標準,String.prototype.length 理論值可以到 2^53-1

我是想不到哪一種 ActionType 可以在這限制下撞名啦….囧