■P159

────────────────
import { useState } from "react";

const AccordionItem = ({ title, children }) => {
  // アコーディオンの開閉状態を定義
  const [isOpen, setIsOpen] = useState(false);

  // 開閉状態を切り替える関数
  const handleOpenToggle = () => {
    setIsOpen(!isOpen);
  };

  return (
    <div>
      <button onClick={handleOpenToggle}>{title}</button>
      {isOpen && <div>{children}</div>}
    </div>
  );
};

const Accordion = () => {
  return (
    <div>
      <AccordionItem title="アコーディオン1">
        アコーディオン1のコンテンツ
      </AccordionItem>
      <AccordionItem title="アコーディオン2">
        アコーディオン2のコンテンツ
      </AccordionItem>
    </div>
  );
};

export default Accordion;
────────────────


■P160

────────────────
import { useState } from "react";

// 開閉状態とそれを切り替える関数はpropsとして受け取る
const AccordionItem = ({ title, children, isOpen, onToggle }) => {
  return (
    <div>
      <button onClick={onToggle}>{title}</button>
      {isOpen && <div>{children}</div>}
    </div>
  );
};
────────────────


■P161

────────────────
const Accordion = () => {
  // 現在開いているアコーディオンのインデックスを定義
  const [openIndex, setOpenIndex] = useState(null);

  // 開閉状態を切り替える関数
  const handleToggle = (index) => {
    setOpenIndex((prevIndex) => (prevIndex === index ? null : index));
  };

  return (
    <div>
      <AccordionItem
        title="アコーディオン1"
        isOpen={openIndex === 1}
        onToggle={() => handleToggle(1)}
      >
        アコーディオン1のコンテンツ
      </AccordionItem>
      <AccordionItem
        title="アコーディオン2"
        isOpen={openIndex === 2}
        onToggle={() => handleToggle(2)}
      >
        アコーディオン2のコンテンツ
      </AccordionItem>
    </div>
  );
};

export default Accordion;
────────────────


■P165

src/App.jsx
────────────────
import { useState } from "react";
import { Content } from "./components/Content";
import { Footer } from "./components/Footer";
import { Header } from "./components/Header";

const App = () => {
  // アプリケーション全体で利用するテーマの状態を定義
  const [theme, setTheme] = useState("light");

  return (
    <div>
      <Header theme={theme} setTheme={setTheme} />
      <Content theme={theme}>
        メインコンテンツが入ります
      </Content>
      <Footer theme={theme} />
    </div>
  );
};

export default App;
────────────────


■P166

src/components/Header.jsx
────────────────
export const Header = ({ theme, setTheme }) => {
  // テーマの状態によって色が切り替わる
  const backgroundColor = theme === "light" ? "#00a2d6" : "#1c68b2";

  // テーマを切り替える関数
  const handleThemeToggle = () => {
    setTheme(prevTheme => (prevTheme === "light" ? "dark" : "light"));
  };

  // テーマの状態によってラベルが切り替わる
  const buttonLabel =
    theme === "light" ? "ダークモードに切り替え" : "ライトモードに切り替え";

  return (
    <header
      style={{
        backgroundColor,
        display: "flex",
        justifyContent: "space-between",
        padding: "20px",
      }}
    >
      <p style={{ color: "#fff" }}>グローバルヘッダー</p>
      <button onClick={handleThemeToggle}>{buttonLabel}</button>
    </header>
  );
};
────────────────


■P167

src/components/Footer.jsx
────────────────
export const Footer = ({ theme }) => {
  // テーマの状態によって色が切り替わる
  const backgroundColor =
    theme === "light" ? "#ddd" : "#403a3a";

  const textColor = theme === "light" ? "#000" : "#fff";

  return (
    <div
      style={{
        backgroundColor,
        display: "grid",
        placeItems: "center",
        padding: "40px",
      }}
    >
      <p style={{ color: textColor }}>グローバルフッター</p>
    </div>
  );
};
────────────────

src/components/ThemedBox.jsx
────────────────
export const ThemedBox = ({ theme }) => {
  // テーマの状態によって色が切り替わる
  const backgroundColor =
    theme === "light" ? "#00a2d6" : "#1c68b2";

  return (
    <div
      style={{
        backgroundColor,
        display: "grid",
        placeItems: "center",
        padding: "20px",
      }}
    >
      <p style={{ color: "#fff" }}>
        テーマで色が変わるボックス
      </p>
    </div>
  );
};
────────────────


■P168

src/components/Content.jsx
────────────────
import { ThemedBox } from "./ThemedBox";

export const Content = ({ children, theme }) => {
  return (
    <main
      style={{
        backgroundColor: "#fcfcfc",
        display: "grid",
        placeItems: "center",
        gap: "20px",
        padding: "40px",
      }}
    >
      {children}
      <ThemedBox theme={theme} />
    </main>
  );
};
────────────────


■P169

src/components/Content.jsx
────────────────
export const Content = ({ children, theme }) => {
  return (
    <main
      …省略…
      <ThemedBox theme={theme} />
    </main>
  );
};
────────────────

