Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 46 additions & 7 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,54 @@
const useCombinedReducers = combinedReducers => {
// Global State
const state = Object.keys(combinedReducers).reduce(
function memoize(fn) {
let lastResult,
//initial last arguments is not going to be the same
// as anything you will pass to the function the first time
lastArguments = [{}];
return (...currentArgs) => {
//returning memoized function
//check if currently passed arguments are the same as
// arguments passed last time
const sameArgs =
currentArgs.length === lastArguments.length &&
lastArguments.reduce(
(result, lastArg, index) =>
result && Object.is(lastArg, currentArgs[index]),
true,
);
if (sameArgs) {
//current arguments are same as last so just
// return the last result and don't execute function
return lastResult;
}
//current arguments are not the same as last time
// or function called for the first time, execute the
// function and set last result
lastResult = fn.apply(null, currentArgs);
//set last args to current args
lastArguments = currentArgs;
//return result
return lastResult;
};
}

const createDispatch = memoize((...dispatchers) => action =>
dispatchers.forEach(fn => fn(action)),
);
const createState = memoize(combinedReducers =>
Object.keys(combinedReducers).reduce(
(acc, key) => ({ ...acc, [key]: combinedReducers[key][0] }),
{},
),
);
const useCombinedReducers = combinedReducers => {
// Global State
const state = createState(combinedReducers);

const dispatchers = Object.values(combinedReducers).map(
([, dispatch]) => dispatch,
);

// Global Dispatch Function
const dispatch = action =>
Object.keys(combinedReducers)
.map(key => combinedReducers[key][1])
.forEach(fn => fn(action));
const dispatch = createDispatch(...dispatchers);

return [state, dispatch];
};
Expand Down
46 changes: 46 additions & 0 deletions src/spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,49 @@ describe('useCombinedReducer', () => {
expect(bCallback.calledOnce).to.eql(true);
});
});

describe('dispatch should not change reference', () => {
const reactDispatch = () => {};
const otherDispatch = () => {};

it('should not create a new dispatch reference if not needed', () => {
const [, dispatch1] = useCombinedReducers({
a: ['1', reactDispatch],
});
const [, dispatch2] = useCombinedReducers({
a: ['1', reactDispatch],
});
expect(dispatch1).to.be.equal(dispatch2);
});
it('should create a new dispatch reference if changed', () => {
const [, dispatch1] = useCombinedReducers({
a: ['1', reactDispatch],
});
const [, dispatch2] = useCombinedReducers({
a: ['1', otherDispatch],
});
expect(dispatch1).to.not.be.equal(dispatch2);
});
});

describe('state should not change reference', () => {
const reactDispatch = () => {};
const otherDispatch = () => {};
const combined = {
a: ['1', reactDispatch],
};
it('should not create a new dispatch reference if not needed', () => {
const [state1] = useCombinedReducers(combined);
const [state2] = useCombinedReducers(combined);
expect(state1).to.be.equal(state2);
});
// it('should create a new dispatch reference if changed', () => {
// const [, dispatch1] = useCombinedReducers({
// a: ['1', reactDispatch],
// });
// const [, dispatch2] = useCombinedReducers({
// a: ['1', otherDispatch],
// });
// expect(dispatch1).to.not.be.equal(dispatch2);
// });
});