Skip to content

Instantly share code, notes, and snippets.

@iMoses
Last active November 7, 2016 14:15
Show Gist options
  • Save iMoses/39bb505d615774f923bd697869ee2a48 to your computer and use it in GitHub Desktop.
Save iMoses/39bb505d615774f923bd697869ee2a48 to your computer and use it in GitHub Desktop.
Immutable Records as stores (minimal example)
import stateRecord from './state-record';
import {
FETCH_SEARCH_RESULTS_LOADING,
FETCH_SEARCH_RESULTS_SUCCESS,
FETCH_SEARCH_RESULTS_FAILURE,
} from './actions';
export default {
stateRecord,
actionHandlers: {
[FETCH_SEARCH_RESULTS_LOADING]: onLoad,
[FETCH_SEARCH_RESULTS_SUCCESS]: onSuccess,
[FETCH_SEARCH_RESULTS_FAILURE]: onFailure,
}
};
function onLoad(state, action) {
state.set('is_loading', true).set('search_query', action.payload.query);
}
function onSuccess(state, action) {
if (state.search_query === action.payload.query)
state.reset().set('search_query', action.payload.query)
.setSearchResults(action.payload.results);
}
function onFailure(state, action) {
if (state.search_query === action.payload.query)
state.reset().set('search_query', action.payload.query);
}
import * as redux from 'redux';
/**
* Custom method for creating immutable reducers out of a state record and an actions map
* @param stateRecord
* @param actionHandlers
* @return {function(state, action): state}
*/
export function immutableReducer({ stateRecord, actionHandlers }) {
return (state, action) => action.type in actionHandlers
? state.withMutations(state => actionHandlers[action.type](state, action))
: state;
}
/**
* Custom method for combining immutable reducers along side standard reducers
* @param reducers
* @return {*}
*/
export function combineImmutableReducers(reducers) {
const immutable_reducers = {};
Object.keys(reducers).forEach(key => {
immutable_reducers[key] = typeof reducers[key] === 'function'
? reducers[key] : immutableReducer(reducers[key]);
});
return redux.combineReducers(immutable_reducers);
}
/**
* Overwrite `createStore` to support immutable reducers
* @param reducers
* @param initialState
* @param middlewares
* @return {*}
*/
export function createStore(reducers, initialState={}, middlewares=[]) {
const createStore = redux.applyMiddleware(...middlewares)(redux.createStore);
if (typeof reducers === 'object') Object.keys(reducers).forEach(key => {
if (typeof reducers[key] === 'object')
initialState[key] = new (reducers[key].stateRecord)(initialState[key]);
});
return createStore(combineImmutableReducers(reducers), initialState);
}
import { Record, List } from 'immutable';
import { SearchResultRecord } from './records';
class stateRecord extends Record({
page_index: 0,
search_query: '',
search_results: List([]),
is_loading: false,
}) {
constructor(props={}) {
super({
...props,
search_results: stateRecord.searchResults(props.search_results || [])
});
}
static searchResults(list=[]) {
return List(list.map(item => new SearchResultRecord(item)));
}
setSearchResults(list) {
return this.set('search_results', stateRecord.searchResults(list));
}
get page_number() {
return this.page_index + 1;
}
get is_empty() {
return this.search_results.size === 0;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment