Last active
December 1, 2018 23:31
-
-
Save likwrk/41be6d28d64228b99a201ec70bdff405 to your computer and use it in GitHub Desktop.
simple Flux implementation inspired by redux refactored with combine reducers and select
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function combineReducers(reducers) { | |
const initState = {}; | |
const finalReducers = Object.keys(reducers).map((key) => { | |
const reducer = reducers[key]; | |
initState[key] = reducers[key](undefined, { type: null }); | |
return { key, reducer }; | |
}); | |
return (state = initState, action) => { | |
const newState = {}; | |
let changed = false; | |
let i = finalReducers.length; | |
while (i--) { | |
const { key, reducer } = finalReducers[i]; | |
const prevState = state[key]; | |
const nextState = reducer(prevState, action); | |
if (!changed && prevState !== nextState) changed = true; | |
newState[key] = nextState; | |
} | |
return changed ? newState : state; | |
}; | |
} | |
function Store(reducer) { | |
let state = reducer(undefined, { type: null }); | |
const subscribers = []; | |
function notifySubscribers(prevState) { | |
let i = subscribers.length; | |
while (i--) { | |
const { callback, select } = subscribers[i]; | |
const value = select ? select(state) : state; | |
const prevValue = select ? select(prevState) : prevState; | |
if (prevValue !== value) callback(value); | |
} | |
} | |
function reduce(action) { | |
if (!action || !action.type) return; | |
const prevState = state; | |
state = reducer(prevState, action); | |
if (state === prevState) return; | |
notifySubscribers(prevState); | |
} | |
this.getState = () => state; | |
this.dispatch = (action) => { | |
if (typeof action === 'function') { | |
action(this.dispatch, this.getState); | |
} else { | |
reduce(action); | |
} | |
}; | |
this.subscribe = (callback, select = null) => { | |
subscribers.push({ callback, select }); | |
return () => { | |
let i = subscribers.length; | |
while (i--) { | |
if (subscribers[i].callback !== callback) continue; | |
subscribers.splice(i, 1); | |
break; | |
} | |
}; | |
}; | |
} | |
/* class Store { | |
constructor(reducer) { | |
this.reducer = reducer; | |
this.state = this.reducer(undefined, { type: null }); | |
this.subscribers = []; | |
this.dispatch = this.dispatch.bind(this); | |
this.getState = this.getState.bind(this); | |
} | |
subscribe(callback, select = null) { | |
this.subscribers.push({ callback, select }); | |
return () => { | |
let i = this.subscribers.length; | |
while (i--) { | |
if (this.subscribers[i].callback !== callback) continue; | |
this.subscribers.splice(i, 1); | |
break; | |
} | |
}; | |
} | |
reduce(action) { | |
if (!action || !action.type) return; | |
const prevState = this.state; | |
this.state = this.reducer(prevState, action); | |
if (this.state === prevState) return; | |
this.notifySubscribers(this.state, prevState); | |
} | |
getState() { | |
return this.state; | |
} | |
notifySubscribers(state, prevState) { | |
let i = this.subscribers.length; | |
while (i--) { | |
const { callback, select } = this.subscribers[i]; | |
const value = select ? select(state) : state; | |
const prevValue = select ? select(prevState) : prevState; | |
if (prevValue !== value) callback(value); | |
} | |
} | |
dispatch(action) { | |
if (typeof action === 'function') { | |
action(this.dispatch, this.getState, this.state); | |
} else { | |
this.reduce(action); | |
} | |
} | |
} */ | |
const counter = (state = 0, action) => { | |
if (action.type !== 'inc') return state; | |
return state + action.value; | |
}; | |
const increment1 = () => ({ type: 'inc', value: 1 }); | |
const increment = value => (dispatch, getState) => { | |
setTimeout(() => { | |
dispatch({ type: 'inc', value }); | |
}, 500); | |
}; | |
const store = new Store(combineReducers({ counter })); | |
console.log(store); | |
store.subscribe((state) => { | |
console.log('subscribe', state); | |
}); | |
const unsubscribe = store.subscribe((state) => { | |
console.log('subscribe with key', state); | |
}, state => state.counter); | |
store.dispatch(increment(2)); | |
store.dispatch(increment1()); | |
unsubscribe(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment