ike81818
@ike81818

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

Uncaught TypeError: xxxxx is not a function を解決したいです

解決したいこと

下記のようなWebサイトで、各カテゴリーをクリックすると、そのカテゴリーで外部データをfetchして、再描画する仕組みを作成中です。
スクリーンショット 2022-07-06 15.24.49.png

画面上部のカテゴリーをクリックしたときは、正常に動作するのですが、
各商品の下部のカテゴリーをクリックすると、
関数を呼び出すところで、
Uncaught TypeError: categorySearchItems is not a function
というエラーが発生してしまいます。
スクリーンショット 2022-07-06 14.52.39.png
スクリーンショット 2022-07-06 16.00.21.png

画面上部のカテゴリーの「トップス」という文字をクリックした場合
および
各商品下部のカテゴリーの「トップス」という文字をクリックした場合
において、
categorySearchItemsの引数newCategoryObjをconsole.logで表示した結果は、いずれも
スクリーンショット 2022-07-06 15.25.36.png
となりました。

実際のサイト https://stalwart-conkies-bbec2c.netlify.app/

サイドバーのカテゴリーを選択すると、抽出結果が表示されるので、
デベロッパーツールを表示した状態で、各カテゴリーをクリックしていただくと、エラーの状況を確認できると思います。

同じ関数categorySearchItemsを使い、引数の内容も同じように見えるにも関わらず、一方のみエラーになってしまうので、原因追求ができなくなってしまいました。

どなたか解決方法を教えていただければ幸いです。

プログラムの構成としは、
pages/index.js                   親コンポーネント
components/searchkey.js  上部カテゴリを表示する子コンポーネント
components/results.js     各商品を表示する子コンポーネント
components/category.js 各商品のカテゴリを表示するresult.jsの子コンポーネント

エラーが発生しているコードは、各商品のカテゴリーを表示するコンポーネント

components/category.js
import styles from "../styles/Home.module.css";
import { CategoryData } from "./categorydata";

const Category = ({ itemcategory, categorySearchItems }) => {
  const handle = (index, categoryObj2) => {
    //let newCategoryObj = ctegoryObjとすると参照コピーになってしまう。ので
    //下記のように完全独立のクローンをコピーする
    let newCategoryObj = {};
    for (let key in categoryObj2) {
      newCategoryObj[key] = categoryObj2[key];
    }

    for (const property in newCategoryObj) {
      newCategoryObj[property] = newCategoryObj[property].slice(0, index + 1);
    }
    
    console.log("newCategoryObj ", newCategoryObj);
 
        // ↓  ↓ ↓ ここでエラーが発生
    categorySearchItems(newCategoryObj);
  };

  let categoryEArr2 = itemcategory.split(",");
  let categoryObj2 = CategoryData.find((element) => {
    return element.categoryEArr.toString() === categoryEArr2.toString();
  });

  return (
    <>
      {categoryObj2 &&
        categoryObj2.categoryJArr.map((cate, index) => {
          return (
            <>
              {index > 0 && <span>  </span>}
              <span
                className={styles.pancategory}
                key={index}
                onClick={(e) => handle(index, categoryObj2)}
              >
                {cate}
              </span>
            </>
          );
        })}
    </>
  );
};
export default Category;

###関連コード 今回関係しそうな部分以外を省略(...の部分)しています。

pages/index.js
import Head from "next/head";
import { useState, useEffect } from "react";
import axios from "axios";
import styles from "../styles/Home.module.css";

import Results from "../components/results";

import Searchkey from "../components/searchkey";


export default function Home() {
 
  const [keyword, setKeyword] = useState(""); //指定キーワード
  const [categoryObj, setCategoryObj] = useState({
    categoryJArr: ["すべて"],
    categoryEArr: [""],
  }); //指定カテゴリ

  const [page, setPage] = useState(1); //現在のページ
  
  const resultsPerPage = 10;
  const [items, setItems] = useState([]); //アイテムの配列
  const [pageCount, setPageCount] = useState(""); //総ページ数

  const options = {
    headers: {
      authorization: `API-TOKEN ${process.env.NEXT_PUBLIC_API_TOKEN}`,
    },
    params: {
      format: "json",
      keyword: keyword,
      // category: category,
      category: categoryObj.categoryEArr.toString(),
      page: page,
      results_per_page: resultsPerPage, //1ページあたりのitem数
    },
  };

...

  const getItems = async () => {
    const res = await axios.get("/api/items", options);
    if (options.params.page == 1 || readMoreFlg == false) {
      setItems(res.data.users.items);
    } else {
      setItems((prev) => {
        return [...prev, ...res.data.users.items];
      });
    }
    setPageCount(res.data.users.pageCount); //総ページ数をセット
  };

  useEffect(() => {
    getItems();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);
...
  // カテゴリーSearch <form>を使用していないので、e.preventDefaultは不要
  const categorySearchItems = (catObj) => {
    // e.preventDefault(); // リロードを止める
    setPage(1);

    setCategoryObj((prev) => catObj);

    options.params.page = 1;
    // options.params.category = categoryE;
    options.params.category = catObj.categoryEArr.toString();
    getItems();
    // scroll_to_top();
  };

...
  return (
    <div className={styles.zentai}>
...
      <div className={styles.container}>
...
        <Searchkey
          keyword={keyword}
          categoryObj={categoryObj}
          categorySearchItems={categorySearchItems}
        />
 ...
        <Results items={items} keyword={keyword} categoryObj={categoryObj} />

...
      </div>
    </div>
  );
}

エラーが発生しているcategory.jsの親コンポーネント

components/results.js
import styles from "../styles/Home.module.css";
import { CategoryData } from "./categorydata";
import Category from "./category";

const Results = ({ items, keyword, categoryObj, categorySearchItems }) => {
 
  return (
    <>
      <div className={styles.results}>
        {items ? (
          items.map((item, index) => {
            
            return (
              <div key={index} className={styles.item}>
            
                <div className={styles.category}>
                  
                  <Category
                    itemcategory={item.category}
                    categorySearchItems={categorySearchItems}
                  />
                </div>
                
              </div>
            );
          })
      </div>
    </>
  );
};
export default Results;

###こちらのコードは、上部のカテゴリーを表示するコンポーネントで、正常に動作します。

components/searchkey.js
import styles from "../styles/Home.module.css";

const Searchkey = ({ keyword, categoryObj, categorySearchItems }) => {
  // categoryObj.categoryJArr.join(" > ");

  const handle = (index) => {
    //let newCategoryObj = ctegoryObjとすると参照コピーになってしまう。ので
    //下記のように完全独立のクローンをコピーする
    let newCategoryObj = {};
    for (let key in categoryObj) {
      newCategoryObj[key] = categoryObj[key];
    }

    for (const property in newCategoryObj) {
      newCategoryObj[property] = newCategoryObj[property].slice(0, index + 1);
    }
    
    console.log("newCategoryObj ", newCategoryObj);
    
    // ↓ ここでエラーは発生しません
    categorySearchItems(newCategoryObj);
  };

  let i = -1;
  return (
    <>
      <div className={styles.searchkey}>
        <div className={styles.keyword}>検索キーワード{keyword}</div>
        <div className={styles.category2}>
          カテゴリー
          {/* {categoryObj.categoryJArr.join(" > ")} */}
          {categoryObj.categoryJArr &&
            categoryObj.categoryJArr.map((cate, index) => {
              i++;
              return (
                <>
                  {/* <label htmlFor="aaa">{cate}</label> */}
                  {i > 0 && <span>  </span>}
                  <span
                    className={styles.pancategory}
                    key={i}
                    onClick={(e) =>
                      // handle(categoryObj.categoryEArr[index], index)
                      handle(index)
                    }
                  >
                    {cate}
                    {/* {categoryObj.categoryEArr[index]} */}
                  </span>
                </>
              );
            })}
        </div>
      </div>
    </>
  );
};

export default Searchkey;
0

2Answer

Uncaught TypeError: categorySearchItems is not a function とは、 categorySearchItems が関数ではないことを意味します。

pages/index.js の下方、

<Results items={items} keyword={keyword} categoryObj={categoryObj} />

categorySearchItems={categorySearchItems} を渡していないせいで、 Results コンポーネントの中で categorySearchItems が undefined になっています。

<Results items={items} keyword={keyword} categoryObj={categoryObj} categorySearchItems={categorySearchItems} />

に直してください。

2Like

Comments

  1. @ike81818

    Questioner

    まったく気づきませんでした。
    バケツリレーを忘れていました。
    お忙しい中、ミスの箇所を見つけていただき、ご丁寧に変更コードまで記載していただきまして、ありがとうございます。
    プログラムを修正して、動作確認できました。

一時経過としてわかったこと書いてきます。
Firefoxでコンソールを見るとここでは?と思うところがあったのですが、

スクリーンショット 2022-07-06 163956.png
こちらの短いのが失敗時の値です 
スクリーンショット 2022-07-06 164045.png
こちらの長いのが上の成功時の値
スクリーンショット 2022-07-06 164130.png

スクリーンショット 2022-07-06 164231.png

スクリーンショット 2022-07-06 164322.png

1Like

Your answer might help someone💌