Ошибка обновления меры элементов DOM с помощью ловушек React - PullRequest
0 голосов
/ 15 мая 2019

Я пытаюсь измерить позицию DOM TreeNodes. Я использую компонент Ant Design Tree (я изменил CSS для отображения в виде диаграммы Org).

Мера, кажется, всегда является предыдущей, а не текущей. Единственная правильная позиция - это первый раз, когда дерево отображается.

Вот репозиторий , чтобы увидеть его в действии:

  • Сначала нажмите, чтобы свернуть дерево
  • Затем нажмите на первый узел. Вы увидите реальное обновление координат.

Я последовал useCallback примеру из документа Реакта.

Я пробовал много разных опций в качестве второго аргумента array внутри моей useLayoutEffect функции. Единственный, кто обновляет координаты, пропускает второй аргумент, но за счет бесконечного цикла .

import * as React from "react";
import { useCallback, useLayoutEffect, useState } from "react";    

export interface TreeNodeProps {
  id: string;
  nodeData: any;
  coordinates?: ClientRect;
}

export const TreeNode: React.FC<TreeNodeProps> = props => {
  const { id, nodeData } = props;
  const [domElement, setDomElement] = useState<HTMLElement>(undefined);
  const [coordinates, setCoordinates] = useState<ClientRect>({
    left: 0,
    right: 0,
    bottom: 0,
    top: 0,
    height: 0,
    width: 0
  });     

  const nodeRef = useCallback((node: HTMLElement) => {
    if (node !== null) {
      setDomElement(node);
      setCoordinates(node.getBoundingClientRect());
    }
  }, []);

  // I tried many combinations for the second argument here
  // the only one that always update is no argument at all so the hook
  // runs in an infinite loop.
  useLayoutEffect(() => {
    domElement &&
      setCoordinates(roundDecimals(domElement.getBoundingClientRect()));
    console.log(props.nodeData.title, JSON.stringify(coordinates, null, 2));
  }, [
    domElement,
    domElement && domElement.getBoundingClientRect().left,
    domElement && domElement.getBoundingClientRect().bottom,
    domElement && domElement.getBoundingClientRect().right
  ]);

  const wbsId = (nodeData && nodeData.wbsId) || "wbsId";
  const title = (nodeData && nodeData.title) || "title";

  return (
    <div ref={nodeRef} id={id} className={styles.treeNode}>
      <p style={{ margin: 0 }}>
        {wbsId} {title}
      </p>
      <div style={{ display: "inline-flex" }}>
        <ul style={{ margin: 0 }}>
          <li>left: {coordinates.left}</li>
          <li>right: {coordinates.right}</li>
        </ul>
        <ul style={{ margin: 0 }}>
          <li>bottom: {coordinates.bottom}</li>
          <li>top: {coordinates.top}</li>
        </ul>
        <ul style={{ margin: 0 }}>
          <li>height: {coordinates.height}</li>
          <li>width: {coordinates.width}</li>
        </ul>
      </div>
    </div>
  );
};
...