0

Having issues with React style not being applied. I have no idea why it is not working as it was before.

See code below:

Accordion.js

import React, {useState} from 'react'

import { risk_assessment } from '../data/questions';

import AccordionItem from '../components/AccordionItem';
import Question from '../components/Question';


const Accordion = props => {
    const [active, setActive] = useState("0")
    
    return (
      <ul className="accordion">
        {risk_assessment.map((question, index) => (
          <AccordionItem 
            key={index}
            itemTitle={question.question}
            itemContent={<Question options={question.options} name={question.name} />} 
            toggle={() => setActive(index)} 
            active={active == index} />
        ))}
      </ul>
    )
}

export default Accordion

AccordionItem.js

import React, {useRef, useEffect} from 'react'

const AccordionItem = ({ itemTitle, itemContent, toggle, active }) => {
    const accordionContent = useRef()
    let contentHeight = {}
    useEffect(() => {
        contentHeight = active ? {height: accordionContent.current.scrollHeight} : {height: "0px"}
    })

    return (
        <li className="accordion_item">
            <button className="button" onClick={toggle}>
                {itemTitle}
                <span className="control">{active ? "—" : "+"}</span>
            </button>
            <div className="answer_wrapper" ref={accordionContent} style={contentHeight} >
                <div className="answer">{itemContent}</div>
            </div>
        </li>
    )
}

export default AccordionItem

Question.js simply renders the data inside the Accordion Item.

Here is the output from Chrome developer tools. Chrome Developer Tools Output

I have tried messing with the useEffect hook to no success. Changed it to run on every render, only on the first render, added the ref as a dependency etc.

I need to use the useRef hook to get the height of the content area dynamically.

Any help would be appreciated.

Courtney
  • 309
  • 2
  • 10

1 Answers1

1

In your case when the component re-renders the value of your variable will be lost. Try putting contentHeight in a state.

  const [contentHeight, setContentHeight] = useState({})
    useEffect(() => {
      setContentHeight(active ? {height: accordionContent.current.scrollHeight} : {height: "0px"});
  }, [active])

You can find more information in this post.

Kelvin
  • 56
  • 5
  • Sorry, I forgot to mention that I tried this. It ends up just infinitely rendering. I also tried adding dependencies to the useEffect hook to control this but no luck there either. It just doesn't toggle when I do this. – Courtney Aug 03 '22 at 06:18
  • You can try to add `active` only as the dependency, adding `contentHeight` caused it to infinitely re-render. – Kelvin Aug 03 '22 at 06:40
  • Amazing, this worked. Anywhere I can find some resources so I can get a deeper understanding of these concepts? Will be nice to be bale to spot these sorts of design issues and be able to implement. – Courtney Aug 03 '22 at 07:15
  • Also, why was it not updating to the latest value the way I initially had it? My line of reasoning was that the Accordion would have its state updated, and then it would rerender everything. For the AccordionItem, wouldn't the useEffect hook run and update the variable and render with the updated height? – Courtney Aug 03 '22 at 07:20
  • You may refer to this [docs](https://beta.reactjs.org/apis/usestate) for deeper understanding on how `userState` works. – Kelvin Aug 03 '22 at 09:49