简体   繁体   中英

Getting "TypeError: cannot read classList of undefined" for FAQ toggle in React

How do I alter this JS so it works inside of a react component? When I add an onClick handler to the span button I get "cannot read property classList of undefined". This was JS taken out of a non react project so I understand that I'm probably not doing this as best practice, but need the direction to make it work.

Here is my code.

 import React from "react" const Faq = () => { const toggleFAQ = function(question) { if( question.parentElement.classList.contains('is-opened') ) { question.parentElement.classList.remove('is-opened'); } else { question.parentElement.classList.add('is-opened'); } } if( document.querySelector('.faq') !== null ) { const questions = Array.from( document.getElementsByClassName('faq__question') ); questions[0].parentElement.classList.add('is-opened'); questions.forEach((question) => { question.addEventListener('click', (e) => toggleFAQ(question)); }) } return ( <> <section className="faq"> <div className="faq__inner"> <h2 className="faq__title">Frequently Asked Questions</h2> <ul className="faq__list"> <li className="faq__item"> <h3 className="faq__question"> How do I make this work? <span className="faq__question-btn" onClick={toggleFAQ}></span> </h3> <article className="faq__answer is-opened"> <div className="faq__answer-inner is-opened"> <p> Lorem Ipsum </p> </div> </article> </li> <li className="faq__item"> <h3 className="faq__question"> Help me, Lord? <span className="faq__question-btn"></span> </h3> <article className="faq__answer"> <div className="faq__answer-inner"> <p> You suck at JS </p> </div> </article> </li> <li className="faq__item"> <h3 className="faq__question"> How does this work. Help? <span className="faq__question-btn"></span> </h3> <article className="faq__answer"> <div className="faq__answer-inner"> <p> Lorem Ipsum. </p> </div> </article> </li> <li className="faq__item"> <h3 className="faq__question"> Lorem Ipsum? <span className="faq__question-btn"></span> </h3> <article className="faq__answer"> <div className="faq__answer-inner"> <p> Lorem ipsum </p> </div> </article> </li> <li className="faq__item"> <h3 className="faq__question"> Lorem Ipsum? <span className="faq__question-btn"></span> </h3> <article className="faq__answer"> <div className="faq__answer-inner"> <p> Lorem Ipsum </p> </div> </article> </li> </ul> </div> </section> </> ) } export default Faq

Thanks in advance!

In React, you don't manipulate the DOM and classLists directly like you are doing / would do in vanilla JS. Instead, it's better to store some state, manipulate the state and then render your view based on the data.

So, I would probably do something like this:

import React, { useState } from "react"

const Faq = () => {
  const [questions, setQuestions] = useState([
    { id: 1, title: 'How do I make this work?', content: 'Lorem Ipsum', isOpen: true },
    { id: 2, title: 'Help me, Lord?', content: 'You suck at JS', isOpen: false },
    { id: 3, title: 'How does this work. Help?', content: 'Lorem Ipsum.', isOpen: false },
    { id: 4, title: 'Lorem Ipsum?', content: 'Lorem ipsum', isOpen: false },
    { id: 5, title: 'Lorem Ipsum?', content: 'Lorem ipsum', isOpen: false },
  ])

  const toggleFAQ = (questionId) => () => {
    const newQuestions = [
      ...questions,
    ]
    const questionIndex = questions.findIndex(q => q.id === questionId)
    newQuestions[questionIndex].isOpen = !newQuestions[questionIndex].isOpen
    setQuestions(newQuestions)
  }
 
  return (
    <section className="faq">
      <div className="faq__inner">
        <h2 className="faq__title">Frequently Asked Questions</h2>
        <ul className="faq__list">
          {questions.map(q => (
            <li key={q.id} className="faq__item">
              <h3 className="faq__question">
                {q.title}
                <span className="faq__question-btn" onClick={toggleFAQ(q.id)}></span>
              </h3>
              <article className={`faq__answer ${q.isOpen ? 'is-opened' : ''}`}>
                <div className={`faq__answer-inner ${q.isOpen ? 'is-opened' : ''}`}>
                  <p>
                    {q.content}
                  </p>
                </div>
              </article>
            </li>
          ))}
        </ul>
      </div>
    </section>
  )
}

export default Faq

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM