Reputation: 436
Question:
Can I render an SVGSVGElement
in React without using dangerouslySetInnerHtml
?
Context:
I am using the vis.js graph library, the getLegend
method returns an SVGSVGElement
object i.e.
const icon = chart.getLegend(args);
In the console I can see this:
in: icon instanceof SVGSVGElement
out: true
in: icon
out: <svg><rect x="0" y="0" width="30" height="30" class="vis-outline"></rect><path class="vis-graph-group0" d="M0,15 L30,15"></path></svg>
Problem:
When I try to render this in react using:
render (
<div> { icon } </div>
)
I get the following error:
Error: Objects are not valid as a React child (found: [object SVGSVGElement]). If you meant to render a collection of children, use an array instead or wrap the object using createFragment(object) from the React add-ons. Check the render method of `LegendElement`
Workaround:
For now I am using:
<svg dangerouslySetInnerHTML={{__html: icon.innerHTML}} />
But I was hoping for a straightforward solution that doesn't use a method with the word dangerous in the name.
Research:
I read this similar question but I don't think it helps for SVG generated at run time: How do I use an SVG in React without using dangerouslySetInnerHTML?
Upvotes: 14
Views: 4986
Reputation: 8773
During development, it is very common to re-render the svg, so I had to do this:
const icon = (...); // SVGSVGElement
const svg = useRef(null);
useEffect(() => {
if (svg.current) {
if (svg.current.firstChild) {
svg.current.replaceChild(icon, svg.current.firstChild)
} else {
svg.current.appendChild(icon)
}
}
}, []);
return <div ref={svg} />
This code prevents from rendering 2+ times.
Upvotes: 1
Reputation: 974
You can simple append the SVGSVGElement using a useRef like this. This example is for a functional component with hooks but can be adapted for class components.
const svg = useRef(null);
useEffect(()=>{
if(svg.current){
svg.current.appendChild(icon)
}
}, []);
return (
<div ref={svg}/>
);
Upvotes: 14