import { createContext, useContext, useState } from "react";
import AccordionItem from "./AccordionItem";
import AccordionTitle from "./AccordionTitle";
import AccordionContent from "./AccordionContent";

export const AccordionContext = createContext();

export function useAccordionContext() {
  const ctx = useContext(AccordionContext);

  if (!ctx) {
    throw new Error(
      "Accordion compound components cannot be rendered outside the Accordion component"
    );
  }
  return ctx;
}

export default function Accordion({ children, className }) {
  const [openItemId, setOpenItemId] = useState(null);

  function toggleItem(id) {
    console.log("Toggling item:", id);
    setOpenItemId((prevId) => (prevId === id ? null : id));
  }

  const contextValue = {
    openItemId,
    toggleItem,
  };

  return (
    <AccordionContext.Provider value={contextValue}>
      <ul className={className}>{children}</ul>
    </AccordionContext.Provider>
  );
}

Accordion.Item = AccordionItem;
Accordion.Title = AccordionTitle;
Accordion.Content = AccordionContent;

 

import { createContext, useContext } from "react";

const AccordionIdContext = createContext();

export function useAccordionId() {
  const context = useContext(AccordionIdContext);

  if (!context) {
    throw new Error("AccordionItem must be used within an AccordionItem");
  }
  return context;
}

export default function AccordionItem({ id, children, className }) {
  return (
    <li className={className}>
      <AccordionIdContext.Provider value={{ id }}>
        {children}
      </AccordionIdContext.Provider>
    </li>
  );
}

 

 

import { useAccordionContext } from "./Accordion";
import { useAccordionId } from "./AccordionItem";

export default function AccordionTitle({ children, className }) {
  const { toggleItem } = useAccordionContext();
  const { id } = useAccordionId();
  return (
    <h3 className={className} onClick={() => toggleItem(id)}>
      {children}
    </h3>
  );
}

 

import { useAccordionContext } from "./Accordion";
import { useAccordionId } from "./AccordionItem";

export default function AccordionContent({ children, className }) {
  const { openItemId } = useAccordionContext();
  const { id } = useAccordionId();

  const isOpen = openItemId === id;

  return (
    <div
      className={
        isOpen ? `${className ?? ""} open` : `${className ?? ""} close`
      }
    >
      {children}
    </div>
  );
}

 

 

꼭 붙어다니는 것들 주로 사용
1. 관련 컴포넌트 들을 논리적으로 그룹화

2. 컴포넌트 사용 시 더 명확한 구조 제공

3. 네임스페이스를 통해 이름 충돌을 방지

+ Recent posts