I just tried to update React to version 16. Unfortunately React Toolbox which I use as UI library is not yet adapted for that.
I took on the quest but stumbled upon something where I could not find a solution
React Toolbox uses React.finDOMNode to do some positioning calculations. After upgrading to React 16 findDomNode is now always returning null and React Toolbox stops working properly.
I tried to isolate the case but I failed. In Isolation React.findDOMNode always returns the correct node.
Isolation code:
import PropTypes from 'prop-types';
import React, {Component} from 'React';
import ReactDOM from 'react-dom';
//import get from 'lodash/get';
//import classNames from 'classnames';
//import css from './css.css';
const yeah = () => {
class YoloComp extends Component {
render = () => (<div {...this.props} >YOLO</div>)
}
return YoloComp;
};
let Yeah = yeah();
export default class Test extends Component {
static propTypes = {};
click = () => {
this.foo();
};
foo = () => {
console.log('ref', this.node);
console.log('dom this', ReactDOM.findDOMNode(this));
console.log('dom node', ReactDOM.findDOMNode(this.node));
};
componentDidMount() {
setTimeout(() => {
this.foo();
});
}
render() {
return (
<Yeah ref={(r) => this.node = r} onClick={this.click}/>
);
}
}
While in React Toolbox for example in the Ripple Component on line 88 it always returns null.
getDescriptor(x, y) {
const { left, top, height, width } = ReactDOM.findDOMNode(this).getBoundingClientRect();
const { rippleCentered: centered, rippleSpread: spread } = this.props;
return {
left: centered ? 0 : x - left - (width / 2),
top: centered ? 0 : y - top - (height / 2),
width: width * spread,
};
}
In most cases I was able to replace findDOMNode with refs but not in that case (A ref in Ripple would reference a React component not an Element) resolving that with React.finDOMNode also returns null.
Best regards Tobias
I ran into the same issue. I'm not familiar enough with React DOM internals to know exactly what changed and if this is just user error on our part, but with a little inspecting I came up with this function that returns the correct DOM node. NB: I'm using private variables here, so use at your own risk.
function dangerouslyFindDOMNode(_reactElement){
try {
console.warn("'dangerouslyFindDOMNode' is liable to break, and often")
let fiberNode = _reactElement._reactInternalFiber
while (fiberNode && !(fiberNode.stateNode instanceof Element)) {
fiberNode = fiberNode.child
}
return fiberNode ? fiberNode.stateNode : null
} catch(e){
console.error(e)
return null
}
}
The code is pretty straightforward; you descend the Fiber node tree until the stateNode
is a DOM element or you run out of children.