Home > Blockchain >  how to render an SVG from a server and still have the option to interpolate JSX into it?
how to render an SVG from a server and still have the option to interpolate JSX into it?

Time:05-28

My goal is to fetch from my own server an SVG and to interpolate the children attribute after the <polygon></polygon> tag.

I am doing this is to add an interactive layer that can be modified by react.

So far I am able to achieve that by serving my SVG via react app, but I want to avoid it for security reasons.

This is my progress so far:

const App = ({children}) => {
  
return (
    <svg
      xmlns="http://www.w3.org/2000/svg"
      width="24"
      height="24"
      viewBox="0 0 24 24"
      fill="none"
      stroke="#6b9bd2"
      stroke-width="3"
      stroke-linecap="round"
      stroke-linejoin="arcs"
    >
  <polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"></polygon>
    {children}
    </svg>
  );
};

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

My ideal solution should look something like this:

import React, { useState, useEffect } from "react";

type ViewBox = {
  x1: string;
  x2: string;
  y1: string;
  y2: string;
};

interface SVGElement {
  svgContent: string;
  viewBox: ViewBox;
}

const App: React.FC = ({ children }) => {
  const [content, setContent] = useState<SVGElement | undefined>();

  useEffect(() => {
    fetch("http://localhost:5000/get-svg-content")
      .then((res) => res.json())
      .then((data) => setContent(data))
      .catch((e) => console.log(e));
  }, []);

  if (content === undefined) return <></>;

  const viewBox = `${content.viewBox.x1} ${content.viewBox.x2} ${content.viewBox.y1} ${content.viewBox.y2}`;
  return (
    <svg viewBox={viewBox}>
      {content.svgContent}
      {children}
    </svg>
  );
};

export default App;


ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

codeSandbox

CodePudding user response:

You should consider using rehype-react - https://github.com/rehypejs/rehype-react.

If you store your SVG as an XML in a database for example, then retrieving it as a string in the client-side, this package allows you to render same string as an SVG (or any other tag).

This method might expose you to XSS, so you should consider using react-sanitize in order to sanitize the string before rendering it.

Using the methods mentioned above, you can render your SVG elements inside the react client, and still implement your component logic around the rendered content.

  • Related