Make numerical refs work in Fiber (#8334)

This commit is contained in:
Ben Alpert
2016-11-17 18:56:33 +00:00
committed by GitHub
parent 862cedee94
commit 8ecb248e6d
5 changed files with 24 additions and 15 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -60,16 +60,16 @@ const {
Deletion,
} = ReactTypeOfSideEffect;
function transferRef(current: ?Fiber, workInProgress: Fiber, element: ReactElement<any>) {
if (typeof element.ref === 'string') {
function coerceRef(current: ?Fiber, element: ReactElement<any>) {
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;
}

View File

@@ -897,7 +897,6 @@ describe('ReactUpdates', () => {
var component = ReactTestUtils.renderIntoDocument(<A />);
console.log('xxx', expect().toThrowError);
expect(() => component.setState({}, 'no')).toThrowError(
'setState(...): Expected the last optional `callback` argument ' +
'to be a function. Instead received: string.'

View File

@@ -273,4 +273,14 @@ describe('ref swapping', () => {
testRefCall();
__DEV__ = originalDev;
});
it('coerces numbers to strings', () => {
class A extends React.Component {
render() {
return <div ref={1} />;
}
}
const a = ReactTestUtils.renderIntoDocument(<A />);
expect(a.refs[1].nodeName).toBe('DIV');
});
});