用 JS Proxy 打造一個狀態管理工具
Proxy 是什麼?
MDN: Proxy 物件被使用於定義基本操作的自定行為(例如:尋找屬性、賦值、列舉、函式調用等等)。
Proxy 是什麼?
Or as I call it...
有人想打聽,或對我們的物件動手腳的時候,我們把他的請求全部攔截下來,然後看我們要幹嘛 (設了一個陷阱)。
Proxy 是什麼?
看 Code 的話
const obj = {
name: 'Kuan',
age: 28,
}
const trappedObj = new Proxy(obj, {
set: (target, key, value) => {
console.log(target, key, value)
},
get: (target, key) => {
console.log(target, key)
}
})
// 觸發 set
trappedObj.name = 'Chun';
// 觸發 get
const b = trappedObj.name;
Proxy 是什麼?
有什麼好處?
-
資料驗證/格式化
-
給預設值
const kuan = new Proxy({is: ''}, {
set: (target, key, value) => {
if (key === 'is' && ['cool', 'handsome'].includes(value)) {
target[key] = value
return true
}
console.error('do you really think of that?!')
}
})
kuan.is = 'ugly'
Proxy 拿來做 Obervable
剛剛說的聽起來好像 event listener?
(事情發生了我要做些什麼)
Proxy 拿來做 Obervable
簡易 obervable
function observe(target, callback) {
return new Proxy(target, {
set: (targetObject, prop, value) => {
callback(prop, value)
targetObject[prop] = value
}
})
}
const myState = observe({}, (key, value) => {
doSomething(key, value)
})
myState.name = 'kuan';
Proxy 拿來做 State Management
參考 redux 的話就要做這些事情:
- state 放在 store 裡面
- store 裡面決定發生了什麼事件要把 state 變成怎樣
- 誰都可以連到這個 store
- 大家透過 dispatch 的方式跟 store 說我要變
Proxy 拿來做 State Management
state 放在 store 裡面:
class Store {
constructor({ state }) {
this.state = state || {};
}
}
Proxy 拿來做 State Management
store 裡面決定發生了什麼事件要把 state 變成怎樣
之 要有可以註冊跟播送事件的東西
class EventController {
constructor() {
this.events = {}
}
subscribe(event, callback) {
if (!this.events.hasOwnProperty(event)) {
this.events[event] = [];
}
return this.events[event].push(callback);
}
publish(event, data = {}) {
if (!this.events.hasOwnProperty(event)) {
this.events[event] = [];
}
return this.events[event].map(callback => callback(data));
}
}
Proxy 拿來做 State Management
store 裡面決定發生了什麼事件要把 state 變成怎樣
之 Store 也要有這個 event controller
class Store {
constructor({ state }) {
this.state = state || {};
this.events = new EventController();
}
}
Proxy 拿來做 State Management
store 裡面決定發生了什麼事件要把 state 變成怎樣
之 Store 要來決定 state 要變怎樣
(透過 mutation)
class Store {
constructor({ state, mutations }) {
this.state = state || {};
this.events = new EventController();
this.mutations = mutations || {};
}
}
type Mutation = (
state: StoreState,
payload: yourData
) => void
Proxy 拿來做 State Management
store 裡面決定發生了什麼事件要把 state 變成怎樣
之 Store 要來決定 state 要變怎樣
(state 是個 proxy)
class Store {
constructor({ state, mutations }) {
this.state = new Proxy(state || {}, {
set: (currentState, key, value) => {
currentState[key] = value;
this.events.publish('stateChange', this.state);
return true
}
});
this.events = new EventController();
this.mutations = mutations || {};
}
}
Proxy 拿來做 State Management
來透過 dispatch 改變 state
class Store {
constructor({ state, mutations }) {
...
}
dispatch(action, payload) {
if(typeof this.mutations[action] !== 'function') {
console.log(`Mutation "${mutation}" doesn't exist`);
return false;
}
const newState = this.mutations[action](this.state, payload);
this.state = Object.assign(this.state, newState);
return;
}
}
Proxy 拿來做 State Management
大家都可以連接 store
const state = {
items: []
}
const mutations = {
addItem(state, payload) {
state.items.push(payload);
return state;
}
}
const store = new Store({
state,
mutations,
})
store.dispatch('addItem', 1)
store.dispatch('addItem', 2)
store.dispatch('addItem', 3)
Proxy 拿來做 State Management
大家都可以連接 store
class Component {
constructor({ store }) {
this.render = (count) => {
document
.querySelector('#root')
.innerHTML = `現在有 ${count} 個東西`;
}
if(store instanceof Store) {
store.events.subscribe('stateChange', ({items}) => {
this.render(items.length)
});
}
}
}
const a = new Component({store})
document.getElementById('btn').addEventListener('click', () => {
store.dispatch('addItem', 1)
})
感ㄣ惜福
其他 reference
用 JS Proxy 打造一個狀態管理工具
By Kai Ting Liu
用 JS Proxy 打造一個狀態管理工具
- 296