Обновление до React 16 findDOMNode перестает работать

Я только что попытался обновить React до версии 16. К сожалению, React Toolbox, который я использую в качестве библиотеки пользовательского интерфейса, еще не адаптирован для этого.

Я взял на себя квест, но наткнулся на то, что я не мог найти решение

React Toolbox использует React.finDOMNode для выполнения некоторых вычислений позиционирования. После обновления до React 16 findDomNode теперь всегда возвращает ноль, и React Toolbox перестает работать должным образом.

Я пытался изолировать дело, но мне не удалось. В Isolation 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, например, в компоненте Ripple в строке 88, он всегда возвращает ноль.

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

В большинстве случаев мне удалось заменить findDOMNode ссылками, но не в этом случае (ссылка в Ripple будет ссылаться на компонент React, а не на элемент), решив, что с помощью React.finDOMNode также возвращается значение null.

  1. Что-то изменилось в React.findDOMNode, чтобы он больше не работал, как в прошлом?
  2. Как я могу принять это изменение во внимание и сделать React TOolbox совместимым с React 16.
  3. Есть ли у вас какие-либо идеи исправить это?

С наилучшими пожеланиями Тобиас

1 ответ

Решение

Я столкнулся с той же проблемой. Я не достаточно знаком с внутренностями React DOM, чтобы точно знать, что изменилось, и если это просто ошибка пользователя с нашей стороны, но после небольшой проверки я придумал эту функцию, которая возвращает правильный узел DOM. NB: здесь я использую приватные переменные, так что используйте на свой страх и риск.

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 или у вас закончились дети.

Другие вопросы по тегам