弹出窗口不会出现在 React 中

Popover does not show up in React

我正在尝试制作一个具有 Treeviz 依赖项的 Web 应用程序。目标是为树的每个节点放置一个弹出按钮,如果用户单击按钮 he/she 可以看到节点的描述,之后它应该是可编辑的。我尝试了很多方法,但对我来说,popover 在 React 中不起作用。

有一个我想做的例子。你可以看到我必须将 React 组件插入 HTML 因此我正在使用 renderToString。您只需查看树的 renderNode 属性。我在 renderNode 中引用 React 组件,例如:${tooltip} ${popover}.

import React from "react";
import { TreevizReact } from "treeviz-react";
import { renderToString } from "react-dom/server";
const data_1 = [
  {
    id: 1,
    text_1: "Chaos",
    description: "Void",
    father: null,
    color: "#FF5722"
  },
  {
    id: 2,
    text_1: "Tartarus",
    description: "Abyss",
    father: 1,
    color: "#FFC107"
  },
  { id: 3, text_1: "Gaia", description: "Earth", father: 1, color: "#8BC34A" },
  { id: 4, text_1: "Eros", description: "Desire", father: 1, color: "#00BCD4" }
];

export const App = () => {
  return (
    <div style={{ marginLeft: 10 }}>
      <div style={{ display: "flex" }}>
        <TreevizReact
          data={data_1}
          relationnalField={"father"}
          nodeWidth={120}
          nodeHeight={80}
          areaHeight={500}
          areaWidth={1000}
          mainAxisNodeSpacing={2}
          secondaryAxisNodeSpacing={2}
          linkShape={"quadraticBeziers"}
          renderNode={(data) => {
            const nodeData = data.data;
            const settings = data.settings;
            let result = "";
            const tooltip = renderToString(
              <strong
                data-toggle="tooltip"
                data-placement="top"
                title={nodeData.description}
              >
                {nodeData.text_1}
              </strong>
            );
            const popover = renderToString(
              <button
                type="button"
                className="btn btn-secondary"
                data-container="body"
                data-toggle="popover"
                data-placement="top"
                data-content={nodeData.description}
              >
                Popover on top
              </button>
            );
            if (data.depth !== 2) {
              result = `<div className="box" 
              style='cursor:pointer;height:${settings.nodeHeight}px; width:${settings.nodeWidth}px;display:flex;flex-direction:column;justify-content:center;align-items:center;background-color:${nodeData.color};border-radius:5px;'>
              <div>
          ${tooltip}
          ${popover}
          </div></div>`;
            } else {
              result = `<div className="box" style='cursor:pointer;height:${
                settings.nodeHeight
              }px; width:${
                settings.nodeHeight
              }px;display:flex;flex-direction:column;justify-content:center;align-items:center;background-color:${
                nodeData.color
              };border-radius:${settings.nodeHeight / 2}px;'><div><strong>
          ${nodeData.text_1}
          </strong></div></div>`;
            }
            return result;
          }}
          duration={600}
          isHorizontal
          linkWidth={(node) => 10}
        />
      </div>
    </div>
  );
};
export default App;

工具提示正常,但未显示弹出窗口。

你可以试试:https://codesandbox.io/s/zealous-orla-4bq5f?file=/src/App.js

也试过

const popover = renderToString(
              <Popup
                trigger={<button> Trigger</button>}
                position="right center"
              >
                <form onSubmit={saveHandler}>
                  <ContentEditable
                    html={text.current}
                    onChange={handleChange}
                  />
                  <button type="submit">Save</button>
                  <button>Cancel</button>
                </form>
              </Popup>
const popoverContent = (
              <Popover id="popover-basic">
                <Popover.Header as="h3">Popover right</Popover.Header>
                <Popover.Body>
                  And here's some <strong>amazing</strong> content. It's very
                  engaging. right?
                </Popover.Body>
              </Popover>
            );

            const popover = renderToString(
              <OverlayTrigger
                trigger="click"
                placement="right"
                overlay={popoverContent}
              >
                <Button variant="success">Click me to see</Button>
              </OverlayTrigger>
            );

None 其中对我有用。

可能您的方法不起作用,因为树中的 dom 元素是动态创建的,并且 .

一种更反应式的方法是使用 react-bootstrap 库并管理状态中的每个 UI 方面。为了实现工具提示,Overlay 组件实际上是一个名为 target 的道具,它允许您更改显示工具提示的元素。

    <Overlay target={tooltipTarget} show={showTooltip} placement="right">
      {(props) => (
        <Tooltip id="overlay-example" {...props}>
          {tooltipNode?.data.text_1}
        </Tooltip>
      )}
    </Overlay>

那么您只需要在 TreevizReact 组件中的 onNodeMouseEnteronNodeMouseLeave 处理程序中管理所有这些状态。

        onNodeMouseEnter={(_event, node) => {
          const t = document.querySelector(`#node-${node.id}`);
          setTooltipTarget(t);
          setShowTooltip(true);
          setTooltipNode(node);
        }}
        onNodeMouseLeave={(_event, node) => {
          setTooltipTarget(null);
          setShowTooltip(false);
          setTooltipNode(null);
        }}

弹出窗口遵循与另一组状态相同的逻辑。

  <div ref={ref}>
    <Overlay
      show={!!selectedNode.current}
      target={target}
      placement="bottom"
      container={ref.current}
      containerPadding={20}
    >
      <Popover id="popover-contained">
        {/* hack to avoid weird blinking (due mutable state) */}
        {!!selectedNode.current && (
          <>
            some form based on node data
            {JSON.stringify(selectedNode.current?.data)}
          </>
        )}
      </Popover>
    </Overlay>
  </div>

并在 onNodeClick 处理程序中

        onNodeClick={(_event, node) => {
          const t = document.querySelector(`#node-${node.id}`);
          // unselect if already selected
          if (selectedNode.current?.id === node.id) {
            selectedNode.current = null;
            setTarget(null);
          } else {
            selectedNode.current = node;
            setTarget(t);
          }
        }}

你可能会注意到这次我通过 ref (selectedNode.current) 使用了一个可变变量,出于某种原因使用状态导致了一些问题,可能是由于 D3 和反应有不同的渲染周期,这就是你的原因在此实施中可能会遇到其他一些故障。

https://codesandbox.io/s/quizzical-buck-slofh?file=/src/App.js