'Refactoring tabs according to react best practices

Here is a FAQ component with a child Accordion. As identifier I use anchor that I get from data, written for every element as tab1, tab2, tab3 etc. (instead of index, because indexes are duplicated when I need render accordion twice or more times).

Accordion requirements is: first element open when page is loaded, previous element closes when next element opens.

My problem is using checking class instead of using state for switching tabs. Please, help me to do it right way according to react rules.

Parent

export const FAQBlock = ({ data }) => {
  const [open, setOpen] = useState(false);
  return (
    <StyledFAQBlock>
        <div className="content">
            {data.items &&
              data.items.map((item, index) => (
                <Accordion
                  key={index}
                  index={index}
                  variant="columns"
                  title={item.title}
                  text={item.text}
                  anchor={item.anchor}
                  faqState={{ open: open, setOpen: setOpen }}
                />
              ))}
        </div>
    </StyledFAQBlock>
  );
};

Child

export const Accordion = props => {
  const { title, text, variant, anchor, faqState } = props;
  const [open, setOpen] = useState(false);
  const bodyRef = useRef(null);
  const contentRef = useRef(null);

  useEffect(() => {
    if (faqState.open === anchor) {
      openAccordion();
    } else {
      closeAccordion();
    }
  }, [faqState.open]);

  useEffect(() => {
    anchor == "tab1" && openAccordion();
  }, []);

  const getContentHeight = () => {
    return contentRef.current.offsetHeight;
  };

  const openAccordion = () => {
    setOpen(true);
    bodyRef.current.style.height = `${getContentHeight()}px`;
  };

  const closeAccordion = () => {
    setOpen(false);
    bodyRef.current.style.height = "0";
  };

  const handleClick = () => {
    if (faqState.open === anchor) {
      if (open) {
        closeAccordion();
      } else {
        openAccordion();
      }
    } else {
      faqState.setOpen(anchor);
    }
  };

  const handleKeyPress = event => {
    if (event.charCode === 13) {
      handleClick();
    }
  };

  return (
    <StyledAccordion className={anchor} variant={variant} open={open}>
      <div
        className="panel"
        onClick={handleClick}
        onKeyPress={handleKeyPress}
        tabIndex="0"
        role="button"
        aria-pressed={open}
      >
        <h3 className="title" dangerouslySetInnerHTML={{ __html: title }} />
      </div>
      <div className="text" ref={bodyRef}>
        <p ref={contentRef} dangerouslySetInnerHTML={{ __html: text }}></p>
      </div>
    </StyledAccordion>
  );
};


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source