Home > Blockchain >  Can you set Mouse hover to identify different elements in React?
Can you set Mouse hover to identify different elements in React?

Time:11-18

I wanted to adapt this code show that, for example if you hovered over a specific , then the relating would also show. useState seems to be the only way to make this work in React as I tried a different example with eventlistner which crashed the page.

const Showstuff = () => {
  const [isHovering, setIsHovering] = useState(false);
  const handleMouseOver = () => {
    setIsHovering(true);
  };
  const handleMouseOut = () => {
    setIsHovering(false);
  };

    return(
        
        <div>
            <div onm ouseOver={handleMouseOver} onm ouseOut={handleMouseOut}>
          Hover over div #1 here
        </div><br /><br />


            <div>
          Hover over div #2 here
        </div>


        {isHovering && (
          <div>
            <h2>Text here visible when hovering div 1</h2>
          </div>
        )}
        </div>
    )
  };
export default Showstuff;


I made multiple useStates for each items as a work around, but this means there's 3x const lines for each item I want to add, and I have 6 elements to hover. Can this be combined into a shorter code? I also tried:

const el = document.getElementById('container');
const hiddenDiv = document.getElementById('hidden-div');

el.addEventListener('mouseover', function handleMouseOver() {
  hiddenDiv.style.visibility = 'visible';
});

el.addEventListener('mouseout', function handleMouseOut() {
  hiddenDiv.style.visibility = 'hidden';
});

from a guide on bobbyhadz website but this would require the same idea of making multiple lines of the same code with different names. This works immediately after saving the page in vscode but then shortly afterwards crashes the page, and does not work - I assume it is not React compatible.

CodePudding user response:

I would do something like this :

function App() {
    const [isHovered, setIsHovered] = useState(null)
    const handleMouseOver = (e) => {
        switch (e.target.id) {
            case "1":
                setIsHovered(1)
                break
            case "2":
                setIsHovered(2)
                break
        }
    }

    return (
        <div className="App">
            <div id="1" onm ouseOver={handleMouseOver} onm ouseOut={() => setIsHovered(null)}>
                DIV 1
            </div>
            <div id="2" onm ouseOver={handleMouseOver} onm ouseOut={() => setIsHovered(null)}>
                DIV 2
            </div>
            {isHovered && <h2>{isHovered === 1 ? "Div 1 is hovered" : "Div 2 is hovered"}</h2>}
        </div>
    )
}

That way you only use one useState hook and set the value of isHovered depending on the targetted div's id.

CodePudding user response:

Instead of having isHovering be a boolean, make it something else. If your design means you can only hover one thing at a time, the simplest solution is to make isHovering just hold some ID. But if you have overlapping elements where it's possible to hover multiple at once, you can use an array of IDs, or an object where each key is an ID and each value is a boolean.

You need to modify your onMouseOver (and, possibly, onMouseOut) function(s) to pass an ID as an argument.

Here is a simple example:

const Showstuff = () => {
  const [isHovering, setIsHovering] = useState();

  const handleMouseOver = (id) => setIsHovering(id);

  const handleMouseOut = () => setIsHovering();

  return (
    <div>
      {[1, 2, 3, 4, 5, 6].map((n) => (
        <>
          <div
            onm ouseOver={() => handleMouseOver(n)}
            onm ouseOut={handleMouseOut}
          >
            {`Hover over div #${n} here`}
          </div>
        </>
      ))}
      {isHovering && (
        <div>
          <h2>{`Text here visible when hovering div ${isHovering}`}</h2>
        </div>
      )}
    </div>
  );
};

You don't have to use a map function if that won't work for you. That's just what I'm doing in this example. Just make sure your IDs are unique.

If you need to be able to hover multiple items at once, you'll have to modify the handleMouseOver and handleMouseOut functions. For example, if you wanted to store the values in an array, you can do something like this:

const handleMouseOver = (id) =>
  setIsHovering((oldIsHovering) => [...oldIsHovering, id]);

const handleMouseOut = (id) =>
  setIsHovering((oldIsHovering) => oldIsHovering.filter((n) => n !== id));

CodePudding user response:

You can use an array as a state variable and map over it:

export default function App() {
  const [isHovering, setIsHovering] = useState(new Array(4).fill(false));

  function handleMouseEnter(i) {
    setIsHovering((prev) => {
      const next = [...prev];
      next[i] = true;
      return next;
    });
  }

  function handleMouseLeave(i) {
    setIsHovering((prev) => {
      const next = [...prev];
      next[i] = false;
      return next;
    });
  }

  return (
    <>
      {isHovering.map((_, i) => (
        <span
          onm ouseEnter={() => handleMouseEnter(i)}
          onm ouseLeave={() => handleMouseLeave(i)}
        ></span>
      ))}
      {isHovering.map((v, i) => (
        <p>
          Hovering on {i}: {v.toString()}
        </p>
      ))}
    </>
  );
}

https://stackblitz.com/edit/react-ts-owprrr?file=App.tsx

This is good if the HTML elements are the same. If all your elements are unique, you are better off using multiple states and naming them uniquely. You'll just end up making the design more confusing by trying to save a few lines of code.

  • Related