更新到 React 16 findDOMNode 停止工作

Update to React 16 findDOMNode stops working

我刚刚尝试将 React 更新到版本 16。不幸的是,我用作 UI 库的 React Toolbox 尚未适用于此。

我接受了这个任务,但偶然发现了一些我找不到解决方案的东西

React Toolbox 使用React.finDOMNode 做一些定位计算。升级到 React 16 后,findDomNode 现在总是返回 null,React Toolbox 停止正常工作。

我试图隔离此案,但我失败了。在隔离中 React.findDOMNode 总是 returns 正确的节点。

隔离码:

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}/>
        );
    }
}

而在 React Toolbox 中,例如第 88 行的 Ripple 组件中,它总是 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,
        };
      }

在大多数情况下,我可以用 refs 替换 findDOMNode 但在那种情况下不行(Ripple 中的 ref 将引用 React 组件而不是元素)用 React.finDOMNode 也 returns null 解决.

  1. React.findDOMNode 有什么变化,以至于它不再像过去那样工作了吗?
  2. 我怎样才能考虑到这一变化并使 React TOolbox 与 React 16 兼容。
  3. 你有解决这个问题的想法吗?

此致 托拜厄斯

我运行遇到了同样的问题。我对 React DOM 内部结构不够熟悉,无法确切知道发生了什么变化,如果这只是我们的用户错误,但经过一些检查,我想出了这个 returns 正确 DOM节点。注意:我在这里使用私有变量,所以使用风险自负。

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

代码非常简单;你下降 Fiber 节点树直到 stateNode 是一个 DOM 元素或者你 运行 out of children.