1

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

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

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

我试图隔离这个案子,但我失败了。在隔离中 React.findDOMNode 总是返回正确的节点。

隔离代码:

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 组件中,它总是返回 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 组件而不是 Element)解决这个问题,React.finDOMNode 也返回 null。

  1. React.findDOMNode 中是否发生了任何变化,以至于它不再像过去那样工作了?
  2. 我怎样才能考虑到这种变化并使 React TOOLbox 与 React 16 兼容。
  3. 你有解决这个问题的想法吗?

最好的问候托比亚斯

4

1 回答 1

2

我遇到了同样的问题。我对 React DOM 内部结构不够熟悉,无法确切知道发生了什么变化,以及这是否只是我们的用户错误,但经过一点检查,我想出了这个返回正确 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 元素或者你用完了子元素。

于 2018-01-16T01:46:43.690 回答