Skip to content

Instantly share code, notes, and snippets.

@kubarskii
Last active February 12, 2024 20:34
Show Gist options
  • Save kubarskii/59b9dfe272d0208779d5b90102898ceb to your computer and use it in GitHub Desktop.
Save kubarskii/59b9dfe272d0208779d5b90102898ceb to your computer and use it in GitHub Desktop.
redux architecture implementation example
class Observer {
#initialValue;
#subscriptions = [];
constructor(initialValue) {
this.#initialValue = initialValue;
}
subscribe(fn) {
this.#subscriptions.push(fn);
}
unsubscribe(fn) {
if (fn) {
const index = this.#subscriptions.indexOf(fn)
if (~index) {
this.#subscriptions.splice(index, 1);
} else {
console.warn('Fn wasn\'t found in subscriptions!')
}
}
}
next(value) {
this.#initialValue = value;
this.#subscriptions.forEach(fn => {
fn.call(null, value)
})
}
get value() {
return this.#initialValue;
}
}
class Store extends Observer {
static #instance;
#reducer;
#defaultActions = {
init: {type: 'INIT'},
}
constructor(reducer) {
super(undefined)
if (Store.#instance) {
throw new Error('Store is already initialized!');
} else {
Store.#instance = this
}
this.#reducer = reducer
this.#init()
}
#init() {
this.dispatch(this.#defaultActions.init)
}
// action: { type: string, payload: any }
dispatch(action) {
const nextState = this.#reducer(this.value, action);
this.next(nextState)
}
}
/*
* @params reducerMap: { [key: string]: () => S }
* returns function
* */
function combineReducers(reducerMap) {
const entries = Object.entries(reducerMap)
return function (state, action) {
const nextState = {}
entries.forEach(([reducerName, reducer]) => {
nextState[reducerName] = reducer(state?.[reducerName], action)
})
return nextState
}
}
const testReducer = (state = {message: 'default state'}, action) => {
const {type, payload} = action;
switch (type) {
case 'TEST':
return {...state, message: 'my name is sasha'};
default:
return state
}
}
const itemsReducer = (state = {items: []}, action) => {
const {type, payload} = action;
switch (type) {
case 'ADD_TASK':
return {...state, items: [...state.items, payload]};
default:
return state
}
}
const rootReducer = combineReducers({test: testReducer, items: itemsReducer})
const store = new Store(rootReducer)
const logger = (value) => {
console.log(value)
}
const logger2 = (value) => {
console.log(value)
}
store.subscribe(logger)
store.subscribe(logger2)
console.log(store.value);
store.dispatch({type: "ADD_TASK", payload: [{status: 'todo', message: 'wash the dog'}]})
store.unsubscribe(logger)
store.unsubscribe(logger)
store.dispatch({type: "ADD_TASK", payload: [{status: 'todo', message: 'wash the dog'}]})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment