Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

191
Views
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 answers
Answer question

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 Report

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 Report

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 Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!