Home > Software engineering >  How do I dynamically add a div where mouse was clicked in React?
How do I dynamically add a div where mouse was clicked in React?

Time:11-23

I'm new to react and wonder how to do weird code stuff. I have a div component that I need to add child divs to depending on where I clicked on the div. I could do this easily in vanilla JS - here is a code sandbox of JS of what I want to do : https://codepen.io/Webasics/pen/YXXyEO

here is what I have in react so far (this is inside my App component):

const imgAdder = (e) => {
  console.log(e.pageX, e.pageY)
}

<main onClick={imgAdder} </main>

$(document).ready(function() {
  $(this).click(function(e) {
    var x = e.pageX;
    var y = e.pageY;
    $('<div/>').css({
      'top': y,
      'left': x
    }).appendTo('body');
  });
});
div {
  background-color: red;
  width: 50px;
  height: 50px;
  position: absolute;
  transform: translate(-50%, -50%);
  /* optional */
  border: 1px solid black;
  /* optional */
}

h2 {
  z-index: 10;
  /* optional */
  /* This always keeps the title on top*/
  position: absolute;
}

body {
  background-color: #E1E7E8;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h2>Click anywhere</h2>

Any directions would be lovely ! thank you.

CodePudding user response:

Weird, but I like it!

https://codesandbox.io/s/elated-meadow-zuerrg?file=/src/App.js

I would simply use useEffect to register a click handler on the document and on click, add elements to a state array.

Finally, render those elements onto the page.

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

export default function App() {
  const elements = useDynamicElements();

  return (
    <>
      <h2>Click anywhere</h2>
      {elements}
    </>
  );
}

const useDynamicElements = () => {
  const [state, setState] = useState([]);

  useEffect(() => {
    const handler = (event) => {
      setState((previous) => [
        ...previous,
        <div style={{ top: event.pageY, left: event.pageX }} />
      ]);
    };
    document.addEventListener("click", handler);
    return () => document.removeEventListener("click", handler);
  });

  return state;
};

CodePudding user response:

function App() {
  // declare array of boxes
  const [boxes, setBoxes] = useState([]);

  const handleClick = ({ pageX, pageY }) => {
    // on every click push a new coordinate to the boxes array
    setBoxes((boxes) => [...boxes, { x: pageX, y: pageY }]);
  };

  return (
    <div className="app" onClick={handleClick}>
      // display boxes
      {boxes.map((box) => (
        // map coordinates to left and top
        <div className="box" style={{ left: box.x, top: box.y }}></div>
      ))}
    </div>
  );
}

Styles, mostly copied from the codepen

.app {
  width: 100%;
  height: 100vh;
}

.box {
  position: absolute;
  width: 50px;
  height: 50px;
  background: red;
  transform: translate(-50%, -50%);
}

sandbox

CodePudding user response:

An over simplified example in React could be like this:

This version can run in the snippets below for convenience.

const App = () => {
  const [boxList, setBoxList] = React.useState([]);

  const handleClick = (e) => {
    if (e.target.classList.contains("btn")) {
      setBoxList([]);
      return;
    }
    setBoxList((prev) => {
      const { pageX, pageY } = e;
      const newBox = { left: pageX, top: pageY };
      return [...prev, newBox];
    });
  };

  return (
    <div className="app" onClick={handleClick}>
      <button className="btn">CLEAN UP</button>
      <h2>Click anywhere</h2>
      {boxList.length > 0 &&
        boxList.map((box, index) => (
          <div className="box" style={{ top: box.top, left: box.left }} key={index}></div>
        ))}
    </div>
  );
};

ReactDOM.render(<App />, document.querySelector("#root"));
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

.app {
  width: 100%;
  height: 100vh;
  background-color: pink;
  position: relative;
}

.box {
  background-color: #000;
  width: 50px;
  height: 50px;
  position: absolute;
  transform: translate(-50%, -50%);
  border: 1px solid black;
}

h2 {
  top: 50%;
  left: 50%;
  position: absolute;
  transform: translate(-50%, -50%);
}

.btn {
  margin: 15px;
  padding: 15px;
  background-color: #fff;
  border: 0;
  border-radius: 12px;
}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.production.min.js"></script>

  • Related