Skip to content

Instantly share code, notes, and snippets.

@thehig
Last active November 22, 2018 13:11
Show Gist options
  • Save thehig/08a1bcabab38f0a0bf063280ee679ef1 to your computer and use it in GitHub Desktop.
Save thehig/08a1bcabab38f0a0bf063280ee679ef1 to your computer and use it in GitHub Desktop.
js: ReduxInjector
/**
* Created by guillaume on 1/17/17.
*/
import { createInjectStore } from 'redux-reducers-injector';
import createSagaMiddleware from 'redux-saga';
import { take, fork, cancel } from 'redux-saga/effects';
export const CANCEL_SAGAS_HMR = 'CANCEL_SAGAS_HMR';
let original_store = {};
function createAbortableSaga(key, saga, store = original_store) {
console.log('createAbortableSaga', key, saga, store);
if (process.env.NODE_ENV === 'development') {
return function* main() {
const sagaTask = yield fork(saga);
const { payload } = yield take(CANCEL_SAGAS_HMR);
if (payload === key) {
yield cancel(sagaTask, store);
}
};
} else {
return saga;
}
}
export const SagaManager = {
startSaga(key, saga, store = original_store) {
console.log('startSaga', key, saga, store);
sagaMiddleware.run(createAbortableSaga(key, saga, store));
},
cancelSaga(key, store = original_store) {
console.log('cancelSaga', key, store);
store.dispatch({
type: CANCEL_SAGAS_HMR,
payload: key
});
}
};
export function reloadSaga(key, saga, store = original_store) {
console.log('reloadSaga', key, saga, store);
SagaManager.cancelSaga(key, store);
SagaManager.startSaga(key, saga, store);
}
export function injectSaga(key, saga, force = false, store = original_store) {
console.log('injectSaga', key, saga, force, store);
// If already set, do nothing, except force is specified
const exists = store.injectedSagas.includes(key);
if (!exists || force) {
if (!exists) {
store.injectedSagas = [...store.injectedSagas, key];
}
if (force) {
SagaManager.cancelSaga(key, store);
}
SagaManager.startSaga(key, saga, store);
}
}
export function createInjectSagasStore(rootSaga, initialReducers, ...args) {
console.log('createInjectSagasStore', rootSaga, initialReducers, args);
original_store = createInjectStore(initialReducers, ...args);
original_store.injectedSagas = [];
injectSaga(
Object.keys(rootSaga)[0],
rootSaga[Object.keys(rootSaga)[0]],
false,
original_store
);
return original_store;
}
export const sagaMiddleware = createSagaMiddleware();
export default createInjectSagasStore;
import { createStore, combineReducers } from 'redux';
import set from 'lodash/set';
import has from 'lodash/has';
let original_store = {};
let combine = combineReducers;
export function combineReducersRecurse(reducers) {
console.log('combineReducersRecurse', reducers);
// If this is a leaf or already combined.
if (typeof reducers === 'function') {
return reducers;
}
// If this is an object of functions, combine reducers.
if (typeof reducers === 'object') {
let combinedReducers = {};
const keys = Object.keys(reducers);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
combinedReducers[key] = combineReducersRecurse(reducers[key]);
}
return combine(combinedReducers);
}
// If we get here we have an invalid item in the reducer path.
const error = {
message: 'Invalid item in reducer tree',
item: reducers
};
console.log(error);
throw new Error(error);
}
export function createInjectStore(initialReducers, ...args) {
console.log('createInjectStore', initialReducers, args);
// If last item is an object, it is overrides.
if (typeof args[args.length - 1] === 'object') {
const overrides = args.pop();
// Allow overriding the combineReducers function such as with redux-immutable.
if (
overrides.hasOwnProperty('combineReducers') &&
typeof overrides.combineReducers === 'function'
) {
combine = overrides.combineReducers;
}
}
original_store = createStore(
combineReducersRecurse(initialReducers),
...args
);
original_store.injectedReducers = initialReducers;
return original_store;
}
export function reloadReducer(key, reducer, store = original_store) {
console.log('reloadReducer', key, reducer, store);
store.replaceReducer(
combineReducersRecurse({ ...store.injectedReducers, [key]: reducer })
);
}
export function injectReducer(
key,
reducer,
force = false,
store = original_store
) {
console.log('injectReducer', key, reducer, force, store);
// If already set, do nothing.
if (!has(store.injectedReducers, key) || force) {
set(store.injectedReducers, key, reducer);
store.replaceReducer(combineReducersRecurse(store.injectedReducers));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment