I have SVG map where i want to display some tooltip when user hovers the element:
const Tooltip = ({ children }) => {
return (
<div className="Tooltip">
<div className="Tooltip--content">
{children}
</div>
</div>
);
}
export default Tooltip
and component
const svgField = () => {
const tooltip = useRef(null);
// methods
const FieldWrapper = styled('div')(({ theme }) => ({
width: '100%',
height: '100%',
position: 'relative',
/* display */
overflow: 'hidden',
'&':{
'alignItems': "center",
'justifyContent': "center"
},
[theme.breakpoints.up('xs')]: {
display: 'none'
},
[theme.breakpoints.up('lg')]: {
display: 'flex'
},
}));
return (
<FieldWrapper >
<div ref={tooltip} style={{position: 'absolute', display: 'none'}}>
<Tooltip>
{currentTooltipInfo}
</Tooltip>
</div>
<svg className="Field--svg"
width={fieldSize[0]}
height={fieldSize[1]}
sx={{
'padding-top':'12px'
}}
>
<g className="field">
{
fields.map((d, i) => (
<path
//
onm ouseMove={(e) => handleMouseMove(e, d)}
/>
))
}
</g>
</svg>
</FieldWrapper >
)
}
now if i use hooks , e.g:
const [tooltipContent, setTooltipContent] = useState(null);
and implement handleMouseMove such as:
const [tooltipContent, setTooltipContent] = useState(null);
const handleMouseMove = (evt, country) => {
tooltip.current.style.display = "block";
tooltip.current.style.left = evt.clientX 10 'px';
tooltip.current.style.top = evt.clientY 10 'px';
tooltip.current.style.border="1px solid black";
setTooltipContent("Some content");
}
wouldnt this re-render whole component including SVG ( which is not small ) and thus affect performance while i need only to re-render tooltip
element?
Is there a way how to rerender only tooltip
element? I am not proficent in React
so every piece of information is appreciated.
Thanks.
CodePudding user response:
If you want to avoid a re-render of the SVG fragment, just extrapolate it in a new Component, and wrap it into React.memo
, that way it won't re-render if the props it receives do not change.
Just make sure you take that Styled Component, FieldWrapper
, out of your Component, since Styled Components must not be declared inside the body of a COmponent, or you are going to recreate a new one at each render.
CodePudding user response:
One option is to memoize the SVG component.
const svg = useMemo(() => (
<svg className="Field--svg"
width={fieldSize[0]}
height={fieldSize[1]}
sx={{
'padding-top': '12px'
}}
>
<g className="field">
{
fields.map((d, i) => (
<path
//
onm ouseMove={(e) => handleMouseMove(e, d)}
/>
))
}
</g>
</svg>
), [fieldSize, fields]);
return (
<FieldWrapper >
<div ref={tooltip} style={{ position: 'absolute', display: 'none' }}>
<Tooltip>
{currentTooltipInfo}
</Tooltip>
</div>
{svg}
</FieldWrapper >
);
This will result in the SVG being recalculated/rerendered only when any of the values in the dependency array change (fieldSize
or fields
).