diff --git a/scripts/fiber/tests-failing.txt b/scripts/fiber/tests-failing.txt index 9e444afc1c..f1161cf0eb 100644 --- a/scripts/fiber/tests-failing.txt +++ b/scripts/fiber/tests-failing.txt @@ -384,7 +384,6 @@ src/renderers/shared/shared/event/__tests__/EventPluginHub-test.js src/renderers/shared/stack/reconciler/__tests__/ReactComponent-test.js * should throw on invalid render targets -* should throw when supplying a ref outside of render method * throws usefully when rendering badly-typed elements src/renderers/shared/stack/reconciler/__tests__/ReactComponentLifeCycle-test.js diff --git a/scripts/fiber/tests-passing.txt b/scripts/fiber/tests-passing.txt index 93d0725443..84d4b53f0f 100644 --- a/scripts/fiber/tests-passing.txt +++ b/scripts/fiber/tests-passing.txt @@ -1019,6 +1019,7 @@ src/renderers/shared/shared/event/eventPlugins/__tests__/ResponderEventPlugin-te * should cancel correctly src/renderers/shared/stack/reconciler/__tests__/ReactComponent-test.js +* should throw when supplying a ref outside of render method * should warn when children are mutated during render * should warn when children are mutated during update * should support refs on owned components @@ -1234,6 +1235,7 @@ src/renderers/shared/stack/reconciler/__tests__/refs-test.js * always has a value for this.refs * ref called correctly for stateless component when __DEV__ = false * ref called correctly for stateless component when __DEV__ = true +* coerces numbers to strings src/renderers/shared/utils/__tests__/accumulateInto-test.js * throws if the second item is null diff --git a/src/renderers/shared/fiber/ReactChildFiber.js b/src/renderers/shared/fiber/ReactChildFiber.js index cd0f7020de..7385372dd8 100644 --- a/src/renderers/shared/fiber/ReactChildFiber.js +++ b/src/renderers/shared/fiber/ReactChildFiber.js @@ -60,16 +60,16 @@ const { Deletion, } = ReactTypeOfSideEffect; -function transferRef(current: ?Fiber, workInProgress: Fiber, element: ReactElement) { - if (typeof element.ref === 'string') { +function coerceRef(current: ?Fiber, element: ReactElement) { + let mixedRef = element.ref; + if (mixedRef != null && typeof mixedRef !== 'function') { if (element._owner) { const ownerFiber : ?Fiber = (element._owner : any); if (ownerFiber && ownerFiber.tag === ClassComponent) { - const stringRef = element.ref; + const stringRef = String(mixedRef); // Check if previous string ref matches new string ref if (current && current.ref && current.ref._stringRef === stringRef) { - workInProgress.ref = current.ref; - return; + return current.ref; } const inst = ownerFiber.stateNode; const ref = function(value) { @@ -77,12 +77,11 @@ function transferRef(current: ?Fiber, workInProgress: Fiber, element: ReactEleme refs[stringRef] = value; }; ref._stringRef = stringRef; - workInProgress.ref = ref; + return ref; } } - } else { - workInProgress.ref = element.ref; } + return mixedRef; } // This wrapper function exists because I expect to clone the code in each path @@ -244,13 +243,13 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { if (current == null || current.type !== element.type) { // Insert const created = createFiberFromElement(element, priority); - transferRef(current, created, element); + created.ref = coerceRef(current, element); created.return = returnFiber; return created; } else { // Move based on index const existing = useFiber(current, priority); - transferRef(current, existing, element); + existing.ref = coerceRef(current, element); existing.pendingProps = element.props; existing.return = returnFiber; return existing; @@ -342,7 +341,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { switch (newChild.$$typeof) { case REACT_ELEMENT_TYPE: { const created = createFiberFromElement(newChild, priority); - transferRef(null, created, newChild); + created.ref = coerceRef(null, newChild); created.return = returnFiber; return created; } @@ -679,7 +678,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { if (child.type === element.type) { deleteRemainingChildren(returnFiber, child.sibling); const existing = useFiber(child, priority); - transferRef(child, existing, element); + existing.ref = coerceRef(child, element); existing.pendingProps = element.props; existing.return = returnFiber; return existing; @@ -694,7 +693,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { } const created = createFiberFromElement(element, priority); - transferRef(currentFirstChild, created, element); + created.ref = coerceRef(currentFirstChild, element); created.return = returnFiber; return created; } diff --git a/src/renderers/shared/stack/reconciler/__tests__/ReactUpdates-test.js b/src/renderers/shared/stack/reconciler/__tests__/ReactUpdates-test.js index f86a015531..5812ce35c0 100644 --- a/src/renderers/shared/stack/reconciler/__tests__/ReactUpdates-test.js +++ b/src/renderers/shared/stack/reconciler/__tests__/ReactUpdates-test.js @@ -897,7 +897,6 @@ describe('ReactUpdates', () => { var component = ReactTestUtils.renderIntoDocument(); - console.log('xxx', expect().toThrowError); expect(() => component.setState({}, 'no')).toThrowError( 'setState(...): Expected the last optional `callback` argument ' + 'to be a function. Instead received: string.' diff --git a/src/renderers/shared/stack/reconciler/__tests__/refs-test.js b/src/renderers/shared/stack/reconciler/__tests__/refs-test.js index 84faf923fe..d5e13b8e22 100644 --- a/src/renderers/shared/stack/reconciler/__tests__/refs-test.js +++ b/src/renderers/shared/stack/reconciler/__tests__/refs-test.js @@ -273,4 +273,14 @@ describe('ref swapping', () => { testRefCall(); __DEV__ = originalDev; }); + + it('coerces numbers to strings', () => { + class A extends React.Component { + render() { + return
; + } + } + const a = ReactTestUtils.renderIntoDocument(); + expect(a.refs[1].nodeName).toBe('DIV'); + }); });