diff --git a/packages/react-dom/src/__tests__/refs-destruction-test.js b/packages/react-dom/src/__tests__/refs-destruction-test.js index bbb24c97e7026..6c6158d6b7512 100644 --- a/packages/react-dom/src/__tests__/refs-destruction-test.js +++ b/packages/react-dom/src/__tests__/refs-destruction-test.js @@ -23,15 +23,31 @@ describe('refs-destruction', () => { ReactDOM = require('react-dom'); ReactTestUtils = require('react-dom/test-utils'); + class ClassComponent extends React.Component { + render() { + return null; + } + } + TestComponent = class extends React.Component { render() { - return ( -
- {this.props.destroy ? null : ( -
Lets try to destroy this.
- )} -
- ); + if (this.props.destroy) { + return
; + } else if (this.props.removeRef) { + return ( +
+
+ +
+ ); + } else { + return ( +
+
+ +
+ ); + } } }; }); @@ -45,7 +61,7 @@ describe('refs-destruction', () => { expect( Object.keys(testInstance.refs || {}).filter(key => testInstance.refs[key]) .length, - ).toEqual(1); + ).toEqual(2); ReactDOM.unmountComponentAtNode(container); expect( Object.keys(testInstance.refs || {}).filter(key => testInstance.refs[key]) @@ -62,7 +78,7 @@ describe('refs-destruction', () => { expect( Object.keys(testInstance.refs || {}).filter(key => testInstance.refs[key]) .length, - ).toEqual(1); + ).toEqual(2); ReactDOM.render(, container); expect( Object.keys(testInstance.refs || {}).filter(key => testInstance.refs[key]) @@ -70,6 +86,23 @@ describe('refs-destruction', () => { ).toEqual(0); }); + it('should remove refs when removing the child ref attribute', () => { + const container = document.createElement('div'); + const testInstance = ReactDOM.render(, container); + expect(ReactTestUtils.isDOMComponent(testInstance.refs.theInnerDiv)).toBe( + true, + ); + expect( + Object.keys(testInstance.refs || {}).filter(key => testInstance.refs[key]) + .length, + ).toEqual(2); + ReactDOM.render(, container); + expect( + Object.keys(testInstance.refs || {}).filter(key => testInstance.refs[key]) + .length, + ).toEqual(0); + }); + it('should not error when destroying child with ref asynchronously', () => { class Modal extends React.Component { componentDidMount() { diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.js b/packages/react-reconciler/src/ReactFiberBeginWork.js index 67b22f96cd837..7e2be7b79c54d 100644 --- a/packages/react-reconciler/src/ReactFiberBeginWork.js +++ b/packages/react-reconciler/src/ReactFiberBeginWork.js @@ -184,7 +184,10 @@ export default function( function markRef(current: Fiber | null, workInProgress: Fiber) { const ref = workInProgress.ref; - if (ref !== null && (!current || current.ref !== ref)) { + if ( + (current === null && ref !== null) || + (current !== null && current.ref !== ref) + ) { // Schedule a Ref effect workInProgress.effectTag |= Ref; }