Here a small demo. There are a few block; hovering on each block appears a tooltip(orange rect). It doesn't work correctly.
Tooltip should be displayed from left or right side. To get sizes of tooltip need to display it. Coords to display tooltip can be calculated only after tooltip is displayed
Codesandbox https://codesandbox.io/s/react-ref-65jj6?file=/src/index.js:88-231
const { useState, useEffect, useCallback } = React; function App() { return ( <div> <HoveredBlock index={1} /> <HoveredBlock index={2} blockStyle={{ marginLeft: "5%" }} /> <HoveredBlock index={3} blockStyle={{ marginLeft: "50%" }} /> </div> ); } function calcCoords(blockRect, hoverRect) { const docWidth = document.documentElement.clientWidth; const isLeft = blockRect.right + hoverRect.width > docWidth; const coords = {}; if (!isLeft) { coords.x = blockRect.right; coords.y = blockRect.top; coords.type = "right"; } else { coords.x = blockRect.left - 5 - hoverRect.width; coords.y = blockRect.top; coords.type = "left"; } return coords; } function HoveredBlock({ index, blockStyle }) { const [blockRect, setBlockRect] = useState(); const [hoverRect, setHoverRect] = useState(); const [showHover, setShowHover] = useState(false); const [coords, setCoords] = useState(); const blockRef = useCallback((node) => { if (node) { setBlockRect(node.getBoundingClientRect()); } }, []); const hoverRef = useCallback( (node) => { if (showHover && node) { setHoverRect(node.getBoundingClientRect()); } }, [showHover] ); useEffect(() => { if (showHover && hoverRect) { const coords = calcCoords(blockRect, hoverRect); setCoords(coords); } }, [hoverRect]); const isHidden = !showHover || !coords ? 'hidden' : ''; return ( <div> <div ref={blockRef} className="block" style={blockStyle} onMouseEnter={() => setShowHover(true)} onMouseLeave={() => setShowHover(false)} > {index} </div> <div ref={hoverRef} className={'hover-block' + isHidden} style={{ left: coords && coords.x, top: coords && coords.y }} /> </div> ); } const rootElement = document.getElementById("root"); ReactDOM.render( <React.StrictMode> <App /> </React.StrictMode>, rootElement );
.block { width: 100px; height: 100px; background-color: aquamarine; margin-left: 82%; } .hover-block { position: fixed; width: 100px; height: 100px; background-color: coral; } .hidden { display: none; }
<script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin></script> <div id="root"></div>
I solved it. I changed the way how to hide element: visibility:hidded
instead of display:none
export default function HoveredBlock({ blockStyle }) {
const [blockRect, setBlockRect] = useState();
const [hoverRect, setHoverRect] = useState();
const [showHover, setShowHover] = useState(false);
const [coords, setCoords] = useState();
const blockRef = useCallback((node) => {
if (node) {
setBlockRect(node.getBoundingClientRect());
}
}, []);
const hoverRef = useCallback((node) => {
if (node) {
setHoverRect(node.getBoundingClientRect());
}
}, []);
useEffect(() => {
if (showHover) {
console.log({ blockRect, hoverRect });
const coords = calcCoords(blockRect, hoverRect);
setCoords(coords);
}
}, [showHover, blockRect, hoverRect]);
return (
<>
<div
ref={blockRef}
className="block"
style={blockStyle}
onMouseEnter={() => setShowHover(true)}
onMouseLeave={() => setShowHover(false)}
/>
<div
ref={hoverRef}
className={cx("hover-block", {
hidden: !showHover || !coords
})}
style={{
left: coords && coords.x,
top: coords && coords.y
}}
></div>
</>
);
}
.block {
width: 100px;
height: 100px;
background-color: aquamarine;
margin-left: 20%;
}
.hover-block {
position: fixed;
width: 100px;
height: 100px;
background-color: coral;
}
.hidden {
visibility: hidden;
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.