Skip to content

Instantly share code, notes, and snippets.

@jdrew1303
Last active July 15, 2018 19:32
Show Gist options
  • Save jdrew1303/878944cafe48e900673416a41a12a385 to your computer and use it in GitHub Desktop.
Save jdrew1303/878944cafe48e900673416a41a12a385 to your computer and use it in GitHub Desktop.
Exploring Redux

Exploring the internals of redux shows how simple and elegant the whole pattern really is, especially middleware. Thunks are a simple and elegant way to handle async actions.

This could probably form the basis of a primative event sourcing system for a backend if we allowed for configuration of a store and some other helpers.

// simple example of how to achieve more declaritive api calls using middleware in redux like frameworks
const apiMiddleare = ({dispatch}) => (next) => (action) => {
return (action.type === '[get] api')
? fetch(action.payload.url)
.then(response => response.json())
.then(json => dispatch({
type: action.payload.success,
payload: json
}))
.catch(error => dispatch({
type: action.payload.failure,
payload: error,
error: true
}))
: next(action);
}
// An example call, note that we tell it the message to be sent on succes or error. We
// could have this use an action creator or class constructor to make it more robust.
store.dispatch({
type: '[get] api',
payload: {
url: 'https://jsonplaceholder.typicode.com/users/4',
success: 'add',
failure: 'error notification'
}
});
const r1 = (state, action) => {
switch(action.type){
case 'add':
return [...state, action.payload];
case 'remove':
return [...state.filter(x => x.id !== action.payload.id)]
default:
return state;
}
}
const actions = [
{
type: 'add',
payload: {
id: 1,
name: 'james'
}
},
{
type: 'add',
payload: {
id: 2,
name: 'another person'
}
},
{
type: 'remove',
payload: {
id: 1
}
},
(dispatch, getState) => {
fetch('https://jsonplaceholder.typicode.com/posts/1')
.then(response => response.json())
.then(json => dispatch({
type: 'add',
payload: json
}))
}
]
const createStore = (reducer, state, middleware) => {
if((typeof state === 'function') && (typeof middleware === 'undefined')){
middleware = state;
state = undefined;
}
if(typeof middleware !== 'undefined') return middleware(createStore)(reducer, state);
const eventList = [];
const getState = () => eventList.reduce(reducer, state);
const dispatch = (action) => {
eventList.push(action);
listeners.forEach(x => x())
}
const listeners = [];
const subscribe = (f) => listeners.push(f);
return {
getState,
dispatch,
subscribe
}
}
const composeReducers = (...reducers) =>
(previousState, action) =>
R.reduce((newState, reducer) => reducer(newState, action), previousState, reducers);
const applyMiddleware = (...middlewares) => (createStore) => (reducer, state, middleware) => {
const store = createStore(reducer, state, middleware);
const dispatch = store.dispatch;
const middlewareAPI = {
getState: store.getState,
dispatch: (action) => dispatch(action)
}
const chain = middlewares.map(m => m(middlewareAPI));
const composedChain = R.compose(...chain);
return {
...store,
dispatch: composedChain(dispatch)
}
}
const thunkMiddleware = ({dispatch, getState}) => (next) => (action) =>
(typeof action === 'function') ? action(dispatch, getState)
: next(action);
const reducers = composeReducers(r1);
const store = createStore(reducers, [], applyMiddleware(thunkMiddleware));
store.subscribe(() => console.log('\n\n\n\n',JSON.stringify(store.getState(), null, 4)));
actions.map(store.dispatch);
store.dispatch((dispatch) => fetch('https://jsonplaceholder.typicode.com/users/1')
.then(response => response.json())
.then(json => dispatch({
type: 'add',
payload: json
})))
window.setTimeout(() => console.log(JSON.stringify(store.getState(), null, 4)), 1000)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment