是否存在不依赖目标ID的React Tooltip解决方案?相关咨询
Absolutely! I’ve run into this exact frustration with ID-dependent tooltips too—especially that annoying querySelector error when using random IDs, and the way it breaks Jest snapshot tests. It’s wild that some popular libraries still force this, but there are plenty of solid ID-free solutions out there:
1. Use react-tooltip with React Refs
This library explicitly supports ref-based targeting instead of IDs, which avoids all selector errors and test flakiness. Here’s a quick example:
import { useRef } from 'react'; import Tooltip from 'react-tooltip'; function ActionButton() { const buttonRef = useRef(null); return ( <> <button ref={buttonRef} className="action-btn"> Hover for Info </button> <Tooltip target={buttonRef} content="No IDs, no chaos!" place="bottom" /> </> ); }
The tooltip uses the ref directly to associate with the target element—no DOM IDs are generated, so your Jest snapshots stay consistent, and you won’t get invalid selector errors.
2. Build a Custom ID-Free Tooltip
If you want full control, you can roll your own using React refs and mouse events to position the tooltip without any IDs. Here’s a minimal implementation:
import { useState, useRef } from 'react'; function IDlessTooltip({ children, content, placement = "bottom" }) { const [isVisible, setIsVisible] = useState(false); const tooltipRef = useRef(null); const targetRef = useRef(null); const positionTooltip = () => { if (!targetRef.current || !tooltipRef.current) return; const targetRect = targetRef.current.getBoundingClientRect(); const tooltipRect = tooltipRef.current.getBoundingClientRect(); const scrollY = window.scrollY; const scrollX = window.scrollX; // Adjust position based on placement if (placement === "bottom") { tooltipRef.current.style.top = `${targetRect.bottom + scrollY + 8}px`; tooltipRef.current.style.left = `${targetRect.left + scrollX + (targetRect.width / 2) - (tooltipRect.width / 2)}px`; } // Add more placement logic (top, left, right) as needed }; const handleMouseEnter = () => { setIsVisible(true); setTimeout(positionTooltip, 0); // Wait for DOM update to calculate position }; const handleMouseLeave = () => setIsVisible(false); return ( <> <div ref={targetRef} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave} style={{ display: "inline-block" }} > {children} </div> {isVisible && ( <div ref={tooltipRef} style={{ position: "absolute", background: "#2d3748", color: "white", padding: "6px 10px", borderRadius: "4px", zIndex: 1000, pointerEvents: "none" }} > {content} </div> )} </> ); } // Usage example function App() { return ( <div style={{ padding: "20px" }}> <IDlessTooltip content="Custom tooltip with no IDs!"> <button>Hover Me</button> </IDlessTooltip> </div> ); }
This implementation uses refs to grab the target element’s position directly, so there’s no need for IDs at all. It’s easy to customize styling and placement, and Jest snapshots won’t be polluted with random IDs.
3. Use Material UI’s Tooltip (Wrapper Approach)
MUI’s Tooltip component uses a wrapper pattern instead of IDs—you just wrap your target element, and it handles the association internally:
import Tooltip from '@mui/material/Tooltip'; import Button from '@mui/material/Button'; function MuiExample() { return ( <Tooltip title="MUI's ID-free tooltip"> <Button variant="contained">Hover for Details</Button> </Tooltip> ); }
Under the hood, MUI uses React’s context and refs to link the tooltip to its target, so no DOM IDs are required. This avoids the querySelector errors and snapshot issues entirely.
Why Do Some Libraries Still Use IDs?
Older tooltip implementations relied on ARIA attributes that required ID associations, but modern libraries have shifted to ref-based or wrapper patterns to avoid these problems. The issue with reactstrap’s Tooltip is likely a holdover from older design choices, but there’s no need to stick with it when better options exist.
内容的提问来源于stack exchange,提问作者ey dee ey em

