diff --git a/scripts/fiber/tests-failing.txt b/scripts/fiber/tests-failing.txt index 9a70a61d8faad..d6bd92c4e817a 100644 --- a/scripts/fiber/tests-failing.txt +++ b/scripts/fiber/tests-failing.txt @@ -86,9 +86,6 @@ src/renderers/shared/shared/__tests__/ReactStatelessComponent-test.js src/renderers/shared/shared/__tests__/ReactUpdates-test.js * marks top-level updates -* throws in setState if the update callback is not a function -* throws in replaceState if the update callback is not a function -* throws in forceUpdate if the update callback is not a function src/renderers/shared/shared/__tests__/refs-test.js * Should increase refs with an increase in divs diff --git a/scripts/fiber/tests-passing.txt b/scripts/fiber/tests-passing.txt index e78188ac61a67..4e3142875d545 100644 --- a/scripts/fiber/tests-passing.txt +++ b/scripts/fiber/tests-passing.txt @@ -1564,6 +1564,9 @@ src/renderers/shared/shared/__tests__/ReactUpdates-test.js * should queue updates from during mount * calls componentWillReceiveProps setState callback properly * does not call render after a component as been deleted +* throws in setState if the update callback is not a function +* throws in replaceState if the update callback is not a function +* throws in forceUpdate if the update callback is not a function * does not update one component twice in a batch (#2410) * does not update one component twice in a batch (#6371) * unstable_batchedUpdates should return value from a callback diff --git a/src/renderers/shared/fiber/ReactFiberClassComponent.js b/src/renderers/shared/fiber/ReactFiberClassComponent.js index 99e9a08416a9c..325e3559783bb 100644 --- a/src/renderers/shared/fiber/ReactFiberClassComponent.js +++ b/src/renderers/shared/fiber/ReactFiberClassComponent.js @@ -33,6 +33,31 @@ var invariant = require('invariant'); const isArray = Array.isArray; +function formatUnexpectedArgument(arg) { + var type = typeof arg; + if (type !== 'object') { + return type; + } + var displayName = arg.constructor && arg.constructor.name || type; + var keys = Object.keys(arg); + if (keys.length > 0 && keys.length < 20) { + return `${displayName} (keys: ${keys.join(', ')})`; + } + return displayName; +} + +function validateCallback(callback, callerName) { + if (typeof callback !== 'function') { + invariant( + false, + '%s(...): Expected the last optional `callback` argument to be a ' + + 'function. Instead received: %s.', + callerName, + formatUnexpectedArgument(callback) + ); + } +} + module.exports = function( scheduleUpdate : (fiber : Fiber, priorityLevel : PriorityLevel) => void, getPriorityContext : () => PriorityLevel, @@ -42,18 +67,27 @@ module.exports = function( const updater = { isMounted, enqueueSetState(instance, partialState, callback) { + if (callback) { + validateCallback(callback, 'setState'); + } const fiber = ReactInstanceMap.get(instance); const priorityLevel = getPriorityContext(); addUpdate(fiber, partialState, callback || null, priorityLevel); scheduleUpdate(fiber, priorityLevel); }, enqueueReplaceState(instance, state, callback) { + if (callback) { + validateCallback(callback, 'replaceState'); + } const fiber = ReactInstanceMap.get(instance); const priorityLevel = getPriorityContext(); addReplaceUpdate(fiber, state, callback || null, priorityLevel); scheduleUpdate(fiber, priorityLevel); }, enqueueForceUpdate(instance, callback) { + if (callback) { + validateCallback(callback, 'forceUpdate'); + } const fiber = ReactInstanceMap.get(instance); const priorityLevel = getPriorityContext(); addForceUpdate(fiber, callback || null, priorityLevel);