Home > database >  Add component to useRef object
Add component to useRef object

Time:12-05

How would you add a component inside an useRef object (which is refering to a DOM element)?

const Red = () => {
  return <div className="color">Red</div>;
};

const Black = () => {
  return <div className="color">Black</div>;
};
const Green = () => {
  return <div className="color">Green</div>;
};

const Button = (params) => {
  const clickHandler = () => {
    let boolA = Math.random() > 0.5;

    if (boolA) {
      params.containerRef.current.appendChild(<Red />);
    } else {
      let boolB = Math.random() > 0.5;

      if (boolB) {
        params.containerRef.current.appendChild(<Black />);
      } else {
        params.containerRef.current.appendChild(<Green />);
      }
    }

  };

  return <button onClick={clickHandler}>Click</button>;
};

export default function App() {
  const containerRef = useRef(null);

  return (
    <div className="App">
      <Button containerRef={containerRef} />

      <div ref={containerRef} className="color-container">
        Color components should be placed here !
      </div>
    </div>
  );
}

params.containerRef.current.appendChild(); -> throws an error. I`ve put it to show what I would like to happen.

Also is what I`m doing an anti-pattern/stupid ? Is there another (smarter) way of achieving the above ?

codesandbox link

edit : I forgot some important information to add. Only Button knows and can decide what component will be added.

CodePudding user response:

expecting you want to add multiple colors, something like this would work and don't need the ref:

import { useState } from "react";
import "./styles.css";

const Color = () => {
  return <div className="color">Color</div>;
};

const Button = (params) => {
  return <button onClick={params.onClick}>Click</button>;
};

export default function App() {
  const [colors, setColors] = useState([]);

  return (
    <div className="App">
      <Button onClick={() => setColors((c) => [...c, <Color />])} />

      <div className="color-container">
        {colors}
      </div>
    </div>
  );
}

CodePudding user response:

It's better to have a state that is changed when the button is clicked.

 const [child, setChild] = useState(null);

 const clickHandler = () => {
   setChild(<Color />);
 };
const Button = (params) => {
  return <button onClick={params.onClick}>Click</button>;
};

 <Button onClick={clickHandler} />
 <div className="color-container">
   Color components should be placed here !
   {child}
 </div>

Working sandbox

Edit: Refer to @TheWuif answer if you want multiple Colors to be added upon clicking the button repeatedly

CodePudding user response:

There're several things from your code I think are anti-pattern:

  • Manipulate the real dom directly instead of via React, which is virtual dom
  • Render the Color component imperatively instead of declaratively

Here's the code that uses useState (state displayColor) to control whether <Color /> should be displayed

import { useState } from "react";
import "./styles.css";

const Color = () => {
  return <div className="color">Color</div>;
};

const Button = (props) => {
  return <button onClick={props.clickHandler}>Click</button>;
};

export default function App() {
  const [displayColor, setDisplayColor] = useState(false);

  const clickHandler = () => {
    setDisplayColor(true);
  };

  return (
    <div className="App">
      <Button clickHandler={clickHandler} />

      <div className="color-container">
        Color components should be placed here !{displayColor && <Color />}
      </div>
    </div>
  );
}

Codesandbox

  • Related