Uncaught TypeError: xxxxx is not a function を解決したいです
解決したいこと
下記のようなWebサイトで、各カテゴリーをクリックすると、そのカテゴリーで外部データをfetchして、再描画する仕組みを作成中です。
画面上部のカテゴリーをクリックしたときは、正常に動作するのですが、
各商品の下部のカテゴリーをクリックすると、
関数を呼び出すところで、
Uncaught TypeError: categorySearchItems is not a function
というエラーが発生してしまいます。
画面上部のカテゴリーの「トップス」という文字をクリックした場合
および
各商品下部のカテゴリーの「トップス」という文字をクリックした場合
において、
categorySearchItemsの引数newCategoryObjをconsole.logで表示した結果は、いずれも
となりました。
実際のサイト https://stalwart-conkies-bbec2c.netlify.app/
サイドバーのカテゴリーを選択すると、抽出結果が表示されるので、
デベロッパーツールを表示した状態で、各カテゴリーをクリックしていただくと、エラーの状況を確認できると思います。
同じ関数categorySearchItemsを使い、引数の内容も同じように見えるにも関わらず、一方のみエラーになってしまうので、原因追求ができなくなってしまいました。
どなたか解決方法を教えていただければ幸いです。
プログラムの構成としは、
pages/index.js 親コンポーネント
components/searchkey.js 上部カテゴリを表示する子コンポーネント
components/results.js 各商品を表示する子コンポーネント
components/category.js 各商品のカテゴリを表示するresult.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;
###関連コード 今回関係しそうな部分以外を省略(...の部分)しています。
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の親コンポーネント
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;
###こちらのコードは、上部のカテゴリーを表示するコンポーネントで、正常に動作します。
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;