ike81818
@ike81818

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

アコディオンメニューを作りたいです。

解決したいこと

サイドバーにカテゴリーのアコーディオンメニューを作るために、
下記のようなHTMLコードを作成したいと思っています。
カテゴリーに関するデータは、オブジェクトの形でコンポーネントに持っています。
オブジェクトは、5階層までもっていますが、今回は2階層までものを作ろうと思っています。
 最初に、CategoryData2配列に対して、categoryEの要素数1のものだけにfilterして、親カテゴリだけのオブジェクトを作成します。
それをmap関数で、1件読み込むごとに、categoryJに一致し、かつ要素数2の子カテゴリをmap関数で出力する。
という流れを想定しています。

親カテゴリーを出力したあとの、子カテゴリの抽出をreturn文の中で、どのように書けば、望む処理ができるのかがわかりません。

この考え方自体が間違えているのかもしれません。

なにか良い方法があれば教えていただければ幸いです。

カテゴリーのオブジェクト

components/categorydata2.js
export const CategoryData2 = [
    {
      categoryJ: ["すべて"],
      categoryE: [""],
    },
    {
      categoryJ: ["ファッション"],
      categoryE: ["fashion"],
    },
    {
      categoryJ: ["ファッション", "トップス"],
      categoryE: ["fashion", "tops"],
    },
    {
        categoryJ: ["ファッション", "トップス", "Tシャツ・カットソー"],
        categoryE: ["fashion", "tops", "t-shirtcut-and-sew"],
    },
    {
        categoryJ: ["ファッション", "オールインワン"],
        categoryE: ["fashion", "all-in-one"],
      },
      {
        categoryJ: ["ファッション", "アンサンブル"],
        categoryE: ["fashion", "ensemble"],
      },
    ...

    {
        categoryJ: ["ベビー・キッズ・マタニティ"],
        categoryE: ["babykidsmaternity"],
      },
      {
        categoryJ: ["ベビー・キッズ・マタニティ", "ベビー・幼児"],
        categoryE: ["babykidsmaternity", "baby_infant"],
      },
      {
        categoryJ: ["ベビー・キッズ・マタニティ", "ベビー・幼児", "服・靴・小物"],
        categoryE: ["babykidsmaternity", "baby_infant", "clothes_shoes_accessory"],
      },
      
      ... 

      {
        categoryJ: ["スポーツ"],
        categoryE: ["sports"],
      },
      {
        categoryJ: ["スポーツ", "スポーツウェア・シューズ"],
        categoryE: ["sports", "sportswearshoes"],
      },
      {
        categoryJ: ["スポーツ", "スポーツウェア・シューズ", "スポーツウェア"],
        categoryE: ["sports", "sportswearshoes", "sportswear"],
      },
      ...

]

このようなHTMLコードになるように、Next.jsのコードを書きたいです。

<ul>
    <label htmlFor="menu1">すべて</label>
    <input type="checkbox" id="menu1" class="toggle"/>
    
    <label htmlFor="menu1">ファッション</label>
    <input type="checkbox" id="menu1" class="toggle"/>
      <ul>
        <li>トップス</li>
        <li>オールインワン</li>
        <li>アンサンブル</li>
      </ul>
    
    <label htmlFor="menu1">ベビー・キッズ・マタニティ</label>
    <input type="checkbox" id="menu1" class="toggle"/>
       <ul>
          <li>ベビー・幼児</li>
       </ul>

    <label htmlFor="menu1">すべて</label>
    <input type="checkbox" id="menu1" class="toggle"/>
</ul>

作成しようとしているコード

components/sidebar.js
import styles from "../styles/Home.module.css";
import { SidebarData } from "./sidebardata";
import { CategoryData2 } from "./categorydata2";
import { useState, useEffect } from "react";

const Sidebar = ({ category, setCategory, categoryItems }) => {
  const [sideCategory, setSideCategory] = useState([]);

  const handle = (value) => {
    // setCategory(value.categoryE);
    const categoryE = value.categoryE;
    categoryItems(categoryE);
  };
  
  const handle2 = (topCategory) => {
    let categoryObj = CategoryData2.filter((element) => {
      return (
        element.categoryJ[0] == topCategory && element.categoryJ.length == 2
      );
    });
    if (typeof categoryObj == "undefined") {
      setSideCategory("");
      return "";
    } else {
      setSideCategory(categoryObj);
      // return categoryObj;
    }
  };

  let CategoryData3 = CategoryData2.filter((element) => {
    return element.categoryE.length == 1;
  });

  return (
    <>
      <div className={styles.sidebar}>
        <div className={styles.sidebarmidashi}>カテゴリー</div>
        <ul className={styles.sidebarlist}>
         {CategoryData3.map((value, key) => {
           let categoryArr = category.split(",");
              return (
              <li>
                <label
                  htmlFor={key}
                  key={key}
                  id={categoryArr[0] == value.categoryE[0] ? "active" : ""}
                  className={styles.sidebarrow}
                  onClick={(e) => handle(value)}
                  >
                <div id="categoryJ">{value.categoryJ}</div>
                </label>

                <input type="checkbox" id={key} class="toggle" />


                //ここで、子カテゴリの抽出を行いたいが、よくわからないです。
                {() => handle2(value.categoryJ)}

                <ul className={styles.sidebarlist}>
                 
                  {sideCategory.map((value, key) => {
                    
                    return (
                      <li
                        key={key}
                        id={category == value.categoryE ? "active" : ""}
                        className={styles.sidebarrow}
                        onClick={(e) => handle(value)}
                       
                      >
                        <div id="categoryJ">{value.categoryJ[1]}</div>
                      
                      </li>
                    );
                  })}
                </ul>
              </li>
            );
          })}
        </ul>
      </div>
    </>
  );
};

export default Sidebar;

0

2Answer

大元のオブジェクトを入れ子にすればもっと直感的に書けます.
軽くサンプルを作ってみました.

コンポーネントRcListでリスト項目を表示し,元のオブジェクトにchildrenが存在する場合は再帰的にRcListを表示しています.
何かしら状態を共有する必要があるならコールバックを用意してあげてください.


@github0013@githubさん,
一回答者としての感想ですが,もう少し質問の状況に即した回答をいただければと思います.
エラーメッセージをコピーして検索するくらいなら誰でもできます.
知見を共有するのがこのサイトの目的でもありますので…

1Like

Comments

  1. @ike81818

    Questioner

    私の質問の仕方が、ざっくりしすぎていたために、回答者の方にご迷惑をおかけいたしました。
    お忙しい中、サンプルまで作成していただきありがとうございます。
    参考にさせていたただきます。

Your answer might help someone💌