diff --git a/src/ReplaceTransition.js b/src/ReplaceTransition.js index c1081c59..b80362f4 100644 --- a/src/ReplaceTransition.js +++ b/src/ReplaceTransition.js @@ -28,7 +28,7 @@ class ReplaceTransition extends React.Component { const child = React.Children.toArray(children)[idx]; if (child.props[handler]) child.props[handler](...originalArgs) - if (this.props[handler]) this.props[handler](findDOMNode(this)) + if (this.props[handler]) this.props[handler](this.props.findDOMNode(this)) } render() { @@ -39,6 +39,7 @@ class ReplaceTransition extends React.Component { } = this.props; const [first, second] = React.Children.toArray(children); + delete props.findDOMNode; delete props.onEnter; delete props.onEntering; delete props.onEntered; @@ -76,6 +77,11 @@ ReplaceTransition.propTypes = { return null; }, + findDOMNode: PropTypes.func, }; +ReplaceTransition.defaultProps = { + findDOMNode, +} + export default ReplaceTransition; diff --git a/src/Transition.js b/src/Transition.js index a12cf71f..eeea4f9d 100644 --- a/src/Transition.js +++ b/src/Transition.js @@ -209,7 +209,7 @@ class Transition extends React.Component { if (nextStatus !== null) { // nextStatus will always be ENTERING or EXITING. this.cancelNextCallback() - const node = ReactDOM.findDOMNode(this) + const node = this.props.findDOMNode(this); if (nextStatus === ENTERING) { this.performEnter(node, mounting) @@ -341,6 +341,7 @@ class Transition extends React.Component { delete childProps.appear delete childProps.enter delete childProps.exit + delete childProps.findDOMNode; delete childProps.timeout delete childProps.addEndListener delete childProps.onEnter @@ -427,6 +428,14 @@ Transition.propTypes = { */ exit: PropTypes.bool, + /** + * The function to find the rendered DOM node that is passed to the transition callbacks. + * + * By default ReactDOM.findDOMNode is used. For `React.StrictMode` compatiblity + * another function must be provided. + */ + findDOMNode: PropTypes.func, + /** * The duration of the transition, in milliseconds. * Required unless `addEndListener` is provided. @@ -529,6 +538,7 @@ Transition.defaultProps = { appear: false, enter: true, exit: true, + findDOMNode: ReactDOM.findDOMNode, onEnter: noop, onEntering: noop, diff --git a/test/Transition-test.js b/test/Transition-test.js index 63d30c0e..f0adab77 100644 --- a/test/Transition-test.js +++ b/test/Transition-test.js @@ -469,4 +469,68 @@ describe('Transition', () => { wrapper.setState({ in: false }) }) }) + + describe('findDOMNode', () => { + it('uses ReactDOM.findDOMNode by default', done => { + const expectDiv = jest.fn(node => expect(node.nodeName).toEqual('DIV')); + const handleExited = () => { + expect(expectDiv).toHaveBeenCalled() + + done(); + } + + const wrapper = mount( + + {status =>
{status}
} +
+ ); + + wrapper.setProps({ in: false }); + }) + + it('can receive a custom findDOMNode method', done => { + class StrictModeTransition extends React.Component { + constructor(props) { + super(props); + this.childRef = React.createRef(); + this.findDOMNode = this.findDOMNode.bind(this); + } + + findDOMNode() { + return this.childRef.current; + } + + render() { + return ( + + {status =>
{status}
} +
+ ); + } + } + + const expectSpan = jest.fn(node => expect(node.nodeName).toEqual('SPAN')); + const handleExited = () => { + expect(expectSpan).toHaveBeenCalled(); + + done(); + } + + const wrapper = mount( + + ); + + wrapper.setProps({ in: false }); + }) + }) })