Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

179
Vistas
mouseEnter and mouseLeave work on HTML elements, but not React components?

First time making a React site (using Gatsby).

What I want to happen

On my index page, I'm trying make a Note component appear when the mouse hovers over a Term component.

What is happening

When I add onMouseEnter and onMouseLeave directly to the Term component, the Note never appears. However, if I use a native html element (span in example code below) instead of <Term/>, the Note does appear.

Does it have something to do with the arrow function?

  • Replacing () => setShowNoteB(true) with console.log("in TermB") (sort of) works.
  • But using onMouseEnter={setShowNoteB(true)} results in an infinite loop error.

Is it related to how I'm composing the components? or is a it a limitation of the useState hook? What I'm doing here seems fairly simple/straightforward, but again, I'm new to this, so maybe there's some rule that I don't know about.

Example code

Index page

//index.js

import * as React from 'react';
import { useState } from 'react';
import Term from '../components/term';
import Note from '../components/note';


const IndexPage = () => {
  const [showNoteA, setShowNoteA] = useState(false);
  const [showNoteB, setShowNoteB] = useState(false);

  return (
    <>
      <h1
      >
        <span
          onMouseEnter={() => setShowNoteA(true)}
          onMouseLeave={() => setShowNoteA(false)}
        > TermA* </span>
        {" "} doesn't behave like {" "}
        <Term word="TermB" symbol="†"
          onMouseEnter={() => setShowNoteB(true)}
          onMouseLeave={() => setShowNoteB(false)}
        />
      </h1>

      {showNoteA ? <Note> <p>This is a note for TermA.</p> </Note> : null}
      {showNoteB ? <Note> <p>This is a note for TermB.</p> </Note> : null}
    </>
  );
};

export default IndexPage

Term component

// term.js

import React from 'react';

const Term = ({ word, symbol }) => {

  return (
    <div>
      <span>{word}</span>
      <span>{symbol}</span>
    </div>
  );
};

export default Term;

Note component

// note.js

import * as React from 'react';

const Note = ({ children })=> {
  return (
    <div>
      {children}
    </div>
  )
};

export default Note;
about 4 years ago · Juan Pablo Isaza
2 Respuestas
Responde la pregunta

0

Solution with useEffect, useRef, forwardRef and addEventListener/removeEventListener:

App.js

import React, { useRef } from 'react';

import Term from './Term';

export default function App() {
  const ref = useRef({});

  return (
    <div>
      Lorem ipsum dolor sit amet,{' '}
      <Term ref={ref} word="consectetur" symbol="†" /> adipiscing elit. Morbi
      laoreet <Term ref={ref} word="lacus" /> in dui vestibulum, nec imperdiet
      augue vulputate.
    </div>
  );
}

If you want to add other terms, just create a new Term component and add the ref, word, symbol (optional) props.

Term.js

import React, { useState, useEffect, forwardRef } from 'react';

import Note from './Note';

function Term({ word, symbol }, ref) {
  const [isHovered, setHovered] = useState(false);
  const [currentTerm, setCurrentTerm] = useState('');
  const [currentSymbol, setCurrentSymbol] = useState('');

  useEffect(() => {
    if (ref.current && word) {
      ref.current[word].addEventListener('mouseover', handleMouseover);
      ref.current[word].addEventListener('mouseout', handleMouseout);

      return () => {
        ref.current[word].removeEventListener('mouseover', handleMouseover);
        ref.current[word].removeEventListener('mouseout', handleMouseout);
      };
    }
  }, [ref.current, word]);

  const handleMouseover = () => {
    setHovered(true);
    setCurrentTerm(word);
    setCurrentSymbol(symbol);
  };

  const handleMouseout = () => {
    setHovered(false);
    setCurrentTerm('');
    setCurrentSymbol('');
  };

  return (
    <>
      <span ref={(elem) => (ref.current[word] = elem)}>
        {word}
      </span>
      {isHovered ? <Note word={currentTerm} symbol={currentSymbol} /> : null}
    </>
  );
}

const forwarded = forwardRef(Term);
export default forwarded;

Note.js

import React from 'react';

export default function Note({ word, symbol }) {

  const checkTerm = (term) => {
    switch (term) {
      case 'consectetur':
        return `definition`;
      case 'lacus':
        return `definition`;
      default:
        return null;
    }
  };

  return (
    <div>
      <p>
        {word} {symbol ? symbol : '-'}
      </p>
      <p>{checkTerm(word)}</p>
    </div>
  );
}

Demo: Stackblitz

about 4 years ago · Juan Pablo Isaza Denunciar

0

When you use Components in your JSX, as opposed to (lowercase) HTML tags, any attribute is only passed as prop and has no further effect directly.

<Term
  word="TermB" symbol="†"
  onMouseEnter={() => setShowNoteB(true)}
  onMouseLeave={() => setShowNoteB(false)}
/>

You need to grab the passed prop and assign it to an actual HTML element in the Component's JSX, like this:

const Term = ({ word, symbol, onMouseEnter, onMouseLeave }) => {
  return (
    <div onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}>
      <span>{word}</span> <span>{symbol}</span>
    </div>
  );
};
about 4 years ago · Juan Pablo Isaza Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda