0

I'm creating a tags section in my app similar to the tags section in a new Stack Overflow question form. I'm using the Material UI close icon as shown in this youtube tutorial (I know I installed the Material UI Icons correctly because the demo icons I created work, just the ones I dynamically created using document.createElementNS doesn't work - and the video tutorial is only for vanilla javascript tutorial without React implementation. I'm doing the conversion to React process currently)

I tried force updating/rendering the React app using this answer here on Stack Overflow - React - How to force a function component to render? - but that still doesn't make the Material UI Icon load into the correct SVG form.

My code looks like as follows: (I'm using createElementNS instead of createElement because I'm thinking I need to use the proper capitalized HTML tag for the Material UI Icon to work - ie. -> )

  const formTagContainer = useRef(null);

  function createTag(label) {
    const div = document.createElement("div");
    const closeBtn = document.createElementNS("", `CloseIcon`);
    div.appendChild(closeBtn);
    return div;
  }

  useEffect(() => {
    formTagContainer.current.appendChild(createTag("Jumbotron"));
  }, []);

  return (
    <>
      <div ref={formTagContainer} className="tagContainer" />
    </>
  );

The above code just generates '<div><CloseIcon></CloseIcon></div>' without switching the <CloseIcon></CloseIcon> part into the SVG form of the Close Icon button. When I use the CloseIcon button normally in the JSX tho, it works fine. So I have one working and one non-working version rendered at the same time. Force-rerendering the app doesn't seem to make the icon turn into the SVG format. How could I load the icon dynamically in React?

diedu
  • 19,277
  • 4
  • 32
  • 49
Simon Suh
  • 10,599
  • 25
  • 86
  • 110

1 Answers1

1

You shouldn't manipulate the dom manually when using react, instead store the tags in a state and render them inside the div in the JSX

  const [tags, setTags] = useState([]);

  useEffect(() => {
    setTags([...tags, {label: 'Jumbotron'}])
  }, []);

  return (
    <>
      <div className="tagContainer">
        {tags.map(tag => <div>{tag.label}<CloseIcon /></div>)}
      </div>
    </>
  );

And if you need a default tag just put it the tags state initial value and then you can remove the unnecessary useEffect

const [tags, setTags] = useState([{label: 'Jumbotron'}]);

diedu
  • 19,277
  • 4
  • 32
  • 49
  • thanks so much for the answer!! that totally solves my problem! Now I got an app that working :D – Simon Suh Oct 29 '20 at 00:27
  • I was wondering about how to get around creating dom elements in React but couldn't think of that solution, thanks a bunch! <3 – Simon Suh Oct 29 '20 at 00:27