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

199
Vistas
addEventListener doesn't work on initial render

I'm trying to create simple accordion in React. If I open/refresh whole page, onclick event is not triggered when I click on buttons. It works properly only after I change something in code and component rerenders. No bugs in console and honestly I have no idea what is happening here. Thanks in advance

import { useEffect } from "react"

function FAQ () {
  const accordionBtn = document.querySelectorAll('.accordionTitle')
  const allTexts = document.querySelectorAll('.text')

  useEffect(() => {
    accordionBtn.forEach(function (el) {
      el?.addEventListener('click', toggleAccordion)
    })
  }, [])
 
  function toggleAccordion (el: Event) {
    
    const targetText = (el?.currentTarget as Element).nextElementSibling?.classList
    const target = (el?.currentTarget as Element).classList

    if (!(targetText?.contains('show'))) {
      accordionBtn.forEach(function (el) {
        el.classList.remove('accordionTitleActive')
        allTexts.forEach(function (el) {
          el.classList.remove('show')
        })
      })
      targetText?.add('show')
      target?.add('accordionTitleActive')
    }
  }

  return (
    <div>
      <ul className='accordion'>
        <li>
          <h2 className='accordionTitle'>Title1 </h2>
          <div className='text show'>
            Content1
          </div>
        </li>
        <li>
          <h2 className='accordionTitle'>Title2 </h2>
          <div className='text'>
            Content2
          </div>
        </li>
        <li>
          <h2 className='accordionTitle'>Title3 </h2>
          <div className='text'>
           Content3
          </div>
        </li>
      </ul>
    </div>
  )
}

export default FAQ
about 4 years ago · Juan Pablo Isaza
3 Respuestas
Responde la pregunta

0

When you retrieve the DOM elements at that time, those elements are not even in DOM. If you move the querySelectorAll calls to useEffect it should solve your problem. Remember that useEffect callback is called after the component has been painted on the screen.

But as Andy mentioned in comment above it is strongly not recommended to access DOM directly. Even if you have to(which I don't think is required in your scenario) there is useRef

enter image description here

about 4 years ago · Juan Pablo Isaza Denunciar

0

Here's how I might approach it. It uses state to maintain the number of the accordian, and then you can just adjust the class of the child elements accordingly.

const { useState } = React;

function Example() {

  // Use state to identify the accordian you want open
  const [ show, setShow ] = useState(0);

  // `handleClick` grabs the id from the accordian
  // and then sets the state
  function handleClick(e) {
    const { id } = e.target.parentNode.dataset;
    setShow(Number(id));
  }

  // Now, for each element check to see if the id matches
  // the state and show that text
  return (
    <div onClick={handleClick}>
      <div data-id="1">
        <h3>Accordian one</h3>
        <p className={show === 1 && "show"}>Accordian one text</p>
      </div>
      <div data-id="2">
        <h3>Accordian two</h3>
        <p className={show === 2 && "show"}>Accordian two text</p>
      </div>
      <div data-id="3">
        <h3>Accordian three</h3>
        <p className={show === 3 && "show"}>Accordian three text</p>
      </div>
    </div>
  );
};

// Render it
ReactDOM.render(
  <Example />,
  document.getElementById("react")
);
p { display: none; }
h3:hover { cursor: pointer; }
.show { display: block; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>

about 4 years ago · Juan Pablo Isaza Denunciar

0

I would suggest - Refactor your code to use class-based components. Not that the existing code is ugly, but you should use best practices when it comes to React and rendering html smoothly. Moreover, by doing so, you can also use React Component Lifecycle methods - which will be very handy!

A good article on class based components : Link

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