Estoy tratando de hacer una aplicación web con dependencia de Treeviz. El objetivo es colocar un botón emergente en cada nodo del árbol y, si el usuario hace clic en el botón, puede ver la descripción del nodo, y luego debe ser editable. Lo intenté de muchas maneras, pero para mí, popover no funciona en React.
Hay un ejemplo de lo que me gustaría hacer. Puede ver que tengo que insertar el componente React en HTML, por lo tanto, estoy usando renderToString. Todo lo que tiene que mirar es la propiedad renderNode del árbol. Me refiero al componente React en renderNode como: ${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; La información sobre herramientas funciona, pero la ventana emergente no aparece. 
Puedes probarlo: https://codesandbox.io/s/zealous-orla-4bq5f?file=/src/App.js
También probé
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> );Ninguno de ellos funcionó para mí.
Probablemente su enfoque no funcione porque los elementos dom en el árbol se crean dinámicamente y bootstrap no los configura .
Una forma más reactiva de hacerlo sería usar react-bootstrap lib y administrar cada aspecto de la interfaz de usuario en los estados. Para implementar la información sobre herramientas, el componente Overlay en realidad es un objeto llamado objetivo que le permite cambiar el elemento que se muestra en la información sobre herramientas.
<Overlay target={tooltipTarget} show={showTooltip} placement="right"> {(props) => ( <Tooltip id="overlay-example" {...props}> {tooltipNode?.data.text_1} </Tooltip> )} </Overlay> Luego, solo necesita administrar todos estos estados en los onNodeMouseEnter y onNodeMouseLeave en el componente TreevizReact .
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); }}La ventana emergente sigue la misma lógica con otro conjunto de estados.
<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>y en el controlador 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); } }} Puede notar que esta vez usé una variable mutable a través de una referencia ( selectedNode.current ), por alguna razón, el uso de un estado causó algunos problemas, tal vez debido a D3 y reaccioné con diferentes ciclos de renderizado, por lo que probablemente encontrará otros problemas técnicos. en esta implementación.
https://codesandbox.io/s/quizzical-buck-slofh?file=/src/App.js