Skip to content
Merged
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
17 changes: 11 additions & 6 deletions src/bindActionCreators.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import mapValues from './utils/mapValues'

function bindActionCreator(actionCreator, dispatch) {
return (...args) => dispatch(actionCreator(...args))
}
Expand Down Expand Up @@ -30,14 +28,21 @@ export default function bindActionCreators(actionCreators, dispatch) {
return bindActionCreator(actionCreators, dispatch)
}

if (typeof actionCreators !== 'object' || actionCreators === null || actionCreators === undefined) {
if (typeof actionCreators !== 'object' || actionCreators === null) {
throw new Error(
`bindActionCreators expected an object or a function, instead received ${actionCreators === null ? 'null' : typeof actionCreators}. ` +
`Did you write "import ActionCreators from" instead of "import * as ActionCreators from"?`
)
}

return mapValues(actionCreators, actionCreator =>
bindActionCreator(actionCreator, dispatch)
)
var keys = Object.keys(actionCreators)
var boundActionCreators = {}
for (var i = 0; i < keys.length; i++) {
var key = keys[i]
var actionCreator = actionCreators[key]
if (typeof actionCreator === 'function') {
boundActionCreators[key] = bindActionCreator(actionCreator, dispatch)
}
}
return boundActionCreators
}
27 changes: 17 additions & 10 deletions src/combineReducers.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { ActionTypes } from './createStore'
import isPlainObject from './utils/isPlainObject'
import mapValues from './utils/mapValues'
import pick from './utils/pick'
import warning from './utils/warning'

function getUndefinedStateErrorMessage(key, action) {
Expand Down Expand Up @@ -92,11 +90,18 @@ function assertReducerSanity(reducers) {
* @returns {Function} A reducer function that invokes every reducer inside the
* passed object, and builds a state object with the same shape.
*/

export default function combineReducers(reducers) {
var finalReducers = pick(reducers, (val) => typeof val === 'function')
var sanityError
var reducerKeys = Object.keys(reducers)
var finalReducers = {}
for (var i = 0; i < reducerKeys.length; i++) {
var key = reducerKeys[i]
if (typeof reducers[key] === 'function') {
finalReducers[key] = reducers[key]
}
}
var finalReducerKeys = Object.keys(finalReducers)

var sanityError
try {
assertReducerSanity(finalReducers)
} catch (e) {
Expand All @@ -116,17 +121,19 @@ export default function combineReducers(reducers) {
}

var hasChanged = false
var finalState = mapValues(finalReducers, (reducer, key) => {
var nextState = {}
for (var i = 0; i < finalReducerKeys.length; i++) {
var key = finalReducerKeys[i]
var reducer = finalReducers[key]
var previousStateForKey = state[key]
var nextStateForKey = reducer(previousStateForKey, action)
if (typeof nextStateForKey === 'undefined') {
var errorMessage = getUndefinedStateErrorMessage(key, action)
throw new Error(errorMessage)
}
nextState[key] = nextStateForKey
hasChanged = hasChanged || nextStateForKey !== previousStateForKey
return nextStateForKey
})

return hasChanged ? finalState : state
}
return hasChanged ? nextState : state
}
}
13 changes: 0 additions & 13 deletions src/utils/mapValues.js

This file was deleted.

15 changes: 0 additions & 15 deletions src/utils/pick.js

This file was deleted.

25 changes: 24 additions & 1 deletion test/bindActionCreators.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,24 @@ import * as actionCreators from './helpers/actionCreators'

describe('bindActionCreators', () => {
let store
let actionCreatorFunctions

beforeEach(() => {
store = createStore(todos)
actionCreatorFunctions = { ...actionCreators }
Object.keys(actionCreatorFunctions).forEach(key => {
if (typeof actionCreatorFunctions[key] !== 'function') {
delete actionCreatorFunctions[key]
}
})
})

it('wraps the action creators with the dispatch function', () => {
const boundActionCreators = bindActionCreators(actionCreators, store.dispatch)
expect(
Object.keys(boundActionCreators)
).toEqual(
Object.keys(actionCreators)
Object.keys(actionCreatorFunctions)
)

const action = boundActionCreators.addTodo('Hello')
Expand All @@ -27,6 +34,22 @@ describe('bindActionCreators', () => {
])
})

it('skips non-function values in the passed object', () => {
const boundActionCreators = bindActionCreators({
...actionCreators,
foo: 42,
bar: 'baz',
wow: undefined,
much: {},
test: null
}, store.dispatch)
expect(
Object.keys(boundActionCreators)
).toEqual(
Object.keys(actionCreatorFunctions)
)
})

it('supports wrapping a single function only', () => {
const actionCreator = actionCreators.addTodo
const boundActionCreator = bindActionCreators(actionCreator, store.dispatch)
Expand Down
16 changes: 0 additions & 16 deletions test/utils/mapValues.spec.js

This file was deleted.

16 changes: 0 additions & 16 deletions test/utils/pick.spec.js

This file was deleted.