Home > database >  React: create number of (svg use) elements based on input field
React: create number of (svg use) elements based on input field

Time:10-27

I am starting with React and trying to make a dynamic svg: I'd like to 'bind' the numeric value of the input to the number of circles (<use>) shown on the canvas. However, the {message} state variable does not work in a for loop – I don't know how to create/modify the array. How could I render the {sampleCircles} dynamically? Thanks in advance.

import { useState } from "react";

export default function Svg() {
  const [message, setMessage] = useState(0);
  let sampleCircleCopies = [
    <use href="#originalCircle" x="15" y="15" key="1" />,
    <use href="#originalCircle" x="30" y="30" key="2" />
  ];

  const handleChange = (event) => {
    setMessage(event.target.value);
  };

  return (
    <>
      <svg className="p-0 border-2 mx-auto" width="400" height="400">
        <circle
          cx="50%"
          cy="50%"
          r="10"
          id="originalCircle"
          style={{ fill: "orange" }}
        />

        {sampleCircleCopies}
      </svg>

      <div>
        <input
          type="number"
          className="border-2 mt-2 p-1 rounded-xl"
          onChange={handleChange}
          value={message}
        />
        <h2>Number of cloned circles: {message}</h2>

      </div>
    </>
  );
}

CodePudding user response:

You can use map() to create an array of JSX elements which react will render for you. I'd also use valueAsNumber instead of value. You can of course also embed the map() directly within the JSX.

function Svg() {
  const [message, setMessage] = React.useState(0);
  const sampleCircleCopies = [...new Array(message)].map((_, i) => (
    <use href="#originalCircle" x={Math.floor(200 * Math.random())} y={Math.floor(50 * Math.random())} key={i} />
  ));
  const handleChange = (event) => {
    setMessage(event.target.valueAsNumber);
  };

  return (
    <React.Fragment>
      <svg className="p-0 border-2 mx-auto" width="400" height="400">
        <circle
          cx="50%"
          cy="50%"
          r="10"
          id="originalCircle"
          style={{ fill: "orange" }}
        />
        {sampleCircleCopies}
      </svg>
      <div>
        <input
          type="number"
          className="border-2 mt-2 p-1 rounded-xl"
          onChange={e => handleChange(e)}
          value={message}
        />
        <h2>Number of cloned circles: {sampleCircleCopies.length}</h2>
      </div>
    </React.Fragment>
  );
}

ReactDOM.render(<Svg/>, document.getElementById('root'));
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<div id="root"></div>

I've changed the code a bit to generate random circles every time the count increases in order to show that the code is working and you are getting however many circles you want.

  • Related