Skip to content

Instantly share code, notes, and snippets.

@urban
Last active March 13, 2019 23:42
Show Gist options
  • Save urban/eba9a3cb427babe6c49a9682b6e6fd4e to your computer and use it in GitHub Desktop.
Save urban/eba9a3cb427babe6c49a9682b6e6fd4e to your computer and use it in GitHub Desktop.
// There area lot more checks in the Redux lib but this gets the point across.
function createStore(reducer, initialState) {
let currentState = initialState;
const listeners = [];
function getState() {
return currentState;
}
function subscribe(listener) {
if (typeof listener !== 'function') {
throw new Error('A listener must be a function');
}
listeners.push(listener);
return function unsubscribe() {
const index = listeners.indexOf(listener);
listeners.splice(index, 1);
}
}
function dispatch(action) {
currentState = reducer(currentState, action);
listeners.forEach(listener => listener());
return action;
}
dispatch({ type: 'INIT'});
return {
getState,
subscribe,
dispatch,
};
}
// End the Redux implementation
// Reducer
function reducer(state = { firstName: 'John', lastName: 'Smith' }, action) {
switch (action.type) {
case 'UPDATE_FIRSTNAME':
return {
...state,
firstName: action.payload,
};
case 'UPDATE_LASTNAME':
return {
...state,
lastName: action.payload,
};
default:
return state;
}
}
// Action creators
const updateFirstName = firstName => ({
type: 'UPDATE_FIRSTNAME',
payload: firstName,
});
const updateLastName = lastName => ({
type: 'UPDATE_LASTNAME',
payload: lastName,
});
// Create the store
const store = createStore(reducer);
// Get initial state
console.log(`INITIAL STATE: ${JSON.stringify(store.getState())}`);
// Subscribe to state changes
const unsub = store.subscribe(() => {
console.log(`Subscription fired`, JSON.stringify(store.getState()));
})
// Dispatch an action
store.dispatch(updateFirstName('Tommy'));
// Unsubscribe our listener
unsub();
// Dispatch another action
store.dispatch(updateLastName('Watson'));
// Get the current state
console.log(JSON.stringify(store.getState()));
const createStore = (reducer = (s, a) => s, state = reducer(undefined, {}), enhancer) => {
if (enhancer) {
return enhancer(createStore)(reducer, state)
}
const Callbacks = new Set();
return {
dispatch: action => {
state = reducer(state, action);
Callbacks.forEach(f => f(state));
},
subscribe: f => (Callbacks.add(f), () => Callbacks.delete(f)),
getState: () => state
};
};
const delay = x => new Promise(resolve => { setTimeout(resolve, x) })
const thunk = store => (state, action) => {
console.log('start async')
delay(1000).then(() => {
console.log('end async')
store.dispatch({ type: 'INCREMENT' })
})
}
const middleware = createStore => (...args) => {
const store = createStore(...args)
const middleware = [thunk(store)]
const dispatch = action => {
console.log('before', store.getState())
store.dispatch(action)
middleware.map(f => f(store.getState(), action))
console.log('final', store.getState())
}
return {
...store,
dispatch
}
}
const rootReducer = (state = { counter: 0 }, action) => {
switch (action.type) {
case "INCREMENT":
return { counter: state.counter + 1 };
case "DECREMENT":
return { counter: state.counter - 1 };
default:
return state;
}
}
const store = createStore(rootReducer, undefined, middleware);
const unsubscribe = store.subscribe(state => console.log('after', state));
store.dispatch({ type: "INCREMENT" });
//store.dispatch({ type: "INCREMENT" });
//store.dispatch({ type: "DECREMENT" });
const createStore = (reducer = (s, a) => s, state = reducer(undefined, {}), enhancer) => {
if (enhancer) {
return enhancer(createStore)(reducer, state)
}
const Callbacks = new Set();
return {
dispatch: action => {
state = reducer(state, action);
Callbacks.forEach(f => f(state));
},
subscribe: f => (Callbacks.add(f), () => Callbacks.delete(f)),
getState: () => state
};
};
const middleware = createStore => (...args) => {
const store = createStore(...args)
const dispatch = action => {
console.log('before', store.getState())
store.dispatch(action)
console.log('finally', store.getState())
}
return {
...store,
dispatch
}
}
const rootReducer = (state = { counter: 0 }, action) => {
switch (action.type) {
case "INCREMENT":
return { counter: state.counter + 1 };
case "DECREMENT":
return { counter: state.counter - 1 };
default:
return state;
}
}
const store = createStore(rootReducer, undefined, middleware);
const unsubscribe = store.subscribe(x => console.log('after', x));
store.dispatch({ type: "INCREMENT" });
//store.dispatch({ type: "INCREMENT" });
//store.dispatch({ type: "DECREMENT" });
const createStore = (reducer = (s, a) => s, state = reducer(undefined, {})) => {
const Callbacks = new Set();
return {
dispatch: action => {
state = reducer(state, action);
Callbacks.forEach(f => f(state));
},
subscribe: f => (Callbacks.add(f), () => Callbacks.delete(f)),
getState: () => state
};
};
const globalReducer = (state = {}, action) => state
const timerReducer = (state = { counter: 0 }, action) => {
switch (action.type) {
case "INCREMENT":
return { counter: state.counter + 1 };
case "DECREMENT":
return { counter: state.counter - 1 };
default:
return state;
}
}
const store = createStore((state = { global: undefined, timer: undefined }, action) => {
return {
global: globalReducer(state.global, action),
timer: timerReducer(state.timer, action),
}
});
const unsubscribe = store.subscribe(console.log);
store.dispatch({ type: "INCREMENT" });
store.dispatch({ type: "INCREMENT" });
store.dispatch({ type: "DECREMENT" });
const createStore = (reducer = (s, a) => s, state = reducer(undefined, {})) => {
const Callbacks = new Set();
return {
dispatch: action => {
state = reducer(state, action);
Callbacks.forEach(f => f(state));
},
subscribe: f => (Callbacks.add(f), () => Callbacks.delete(f)),
getState: () => state
};
};
const store = createStore((state = { counter: 0 }, action) => {
switch (action.type) {
case "INCREMENT":
return { counter: state.counter + 1 };
case "DECREMENT":
return { counter: state.counter - 1 };
default:
return state;
}
});
const unsubscribe = store.subscribe(console.log);
store.dispatch({ type: "INCREMENT" });
store.dispatch({ type: "INCREMENT" });
store.dispatch({ type: "DECREMENT" });
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment