冗長的なコードを関数や別ファイルにまとめたいです
解決したいこと
Next.jsを使って、下記のようなコードを書いたのですが、
ページングの部分がコンポーネント化できず、
(子コンポーネントから親コンポーネントへ「ページ番号」を渡すことができないため)
pages/index.jsに直接書きました。
ページングナビは、サイトの上下に2つあるので、同じ長いコードを2つ書きました。
この重複する2つのコード部分を関数化したり、別ファイルにして読み込んだりする方法はあるのでしょうか?
ご教示いただけますと幸いです。
[サイト] https://zesty-faun-47f010.netlify.app/
コード
pages/index.js
import Head from "next/head";
import { useState, useEffect } from "react";
import styles from "../styles/Home.module.css";
import Title from "../components/title";
import Form from "../components/form";
import Sidebar from "../components/sidebar";
import Results from "../components/results";
import Footer from "../components/footer";
export default function Home() {
const [keyword, setKeyword] = useState("犬"); //指定キーワード
const [category, setCategory] = useState(""); //指定カテゴリ
const [page, setPage] = useState(1); //現在のページ
const [resultsPerPage, setResultsPerPage] = useState(10); //1ページあたりのitem数
const [items, setItems] = useState([]); //アイテムの配列
const [pageCount, setPageCount] = useState(""); //総ページ数
const options = {
params: {
keyword: keyword,
category: category,
page: page,
results_per_page: resultsPerPage,
},
};
let readMoreFlg = false;
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
}, []);
// Pagination +
const pageIncrement = () => {
if (page < pageCount) {
const newPage = page + 1;
setPage((prevPage) => prevPage + 1);
options.params.page = newPage;
readMoreFlg = false;
getItems();
}
};
// Pagination -
const pageDecrement = () => {
if (page > 1) {
const newPage = page - 1;
setPage((prevPage) => prevPage - 1);
options.params.page = newPage;
readMoreFlg = false;
getItems();
}
};
const pageChange = (newPage) => {
setPage(newPage);
options.params.page = newPage;
readMoreFlg = false;
getItems();
};
return (
<div className={styles.zentai}>
<div className={styles.container}>
<Head>
<title>総合ショップ</title>
{/* <meta name="viewport" content="width=device-width,initial-scale=1.0" /> */}
{/* <meta name="viewport" content="viewport-fit=cover" /> */}
</Head>
<div id="page_top"></div>
<div className={styles.top}>
<Title reload={reload} />
<Form
category={category}
setKeyword={setKeyword}
setCategory={setCategory}
searchItems={searchItems}
keyword={keyword}
/>
{/* <div style={{ marginTop: "24px" }}> */}
</div>
// ↓ ここからが 上部のページネーションナビ
<div className={styles.paginationT}>
{(() => {
if (pageCount > 0) {
let haba = 2;
let startpage = page - haba;
if (startpage < 2) {
startpage = 2;
}
let endpage = page + haba;
if (endpage >= pageCount) {
endpage = pageCount - 1;
}
pageCount);
const items = [];
if (page > 2) {
items.push(
<button
className={styles.pageButton}
onClick={() => pageDecrement()}
>
前へ
</button>
);
}
items.push(
<button
className={page == 1 ? styles.pageButtonC : styles.pageButton}
onClick={() => pageChange(1)}
>
1
</button>
);
if (startpage >= 3) {
items.push(<button className={styles.pageButton}>...</button>);
}
for (let i = startpage; i <= endpage; i++) {
items.push(
<button
className={
i == page ? styles.pageButtonC : styles.pageButton
}
onClick={() => pageChange(i)}
>
{i}
</button>
);
}
if (endpage <= pageCount - 2) {
items.push(<button className={styles.pageButton}>...</button>);
}
if (pageCount > 1) {
items.push(
<button
className={
page == pageCount ? styles.pageButtonC : styles.pageButton
}
onClick={() => pageChange(pageCount)}
>
{pageCount}
</button>
);
}
if (page < pageCount) {
items.push(
<button
className={styles.pageButton}
onClick={() => pageIncrement()}
>
次へ
</button>
);
}
return <div>{items}</div>;
}
})()}
<div className={styles.pagination2}>
{page} / {pageCount} ページ
</div>
</div>
// ↑ ここまで 上部ページネーションナビ
// サイドバー
<Sidebar
category={category}
setCategory={setCategory}
categoryItems={categoryItems}
/>
//メインコンテンツ
<Results items={items} keyword={keyword} category={category} />
// ↓ ここから 下部のページネーションナビ
<div className={styles.paginationB}>
{(() => {
if (pageCount > 0) {
let haba = 2;
let startpage = page - haba;
if (startpage < 2) {
startpage = 2;
}
let endpage = page + haba;
if (endpage >= pageCount) {
endpage = pageCount - 1;
}
const items = [];
if (page > 2) {
items.push(
<button
className={styles.pageButton}
onClick={() => pageDecrement()}
>
前へ
</button>
);
}
items.push(
<button
className={page == 1 ? styles.pageButtonC : styles.pageButton}
onClick={() => pageChange(1)}
>
1
</button>
);
if (startpage >= 3) {
items.push(<button className={styles.pageButton}>...</button>);
}
for (let i = startpage; i <= endpage; i++) {
items.push(
<button
className={
i == page ? styles.pageButtonC : styles.pageButton
}
onClick={() => pageChange(i)}
>
{i}
</button>
);
}
if (endpage <= pageCount - 2) {
items.push(<button className={styles.pageButton}>...</button>);
}
if (pageCount > 1) {
items.push(
<button
className={
page == pageCount ? styles.pageButtonC : styles.pageButton
}
onClick={() => pageChange(pageCount)}
>
{pageCount}
</button>
);
}
if (page < pageCount) {
items.push(
<button
className={styles.pageButton}
onClick={() => pageIncrement()}
>
次へ
</button>
);
}
return <div>{items}</div>;
}
})()}
<div className={styles.pagination2}>
{page} / {pageCount} ページ
</div>
</div>
// ↑ ここまでが 下部のページネーションナビ
//フッター
<Footer />
</div>
</div>
);
}
下記のようなコードで一応できました
pages/index.js
import Head from "next/head";
import { useState, useEffect } from "react";
import styles from "../styles/Home.module.css";
import Title from "../components/title";
import Form from "../components/form";
import Sidebar from "../components/sidebar";
import Results from "../components/results";
import Footer from "../components/footer";
import Paging from "../components/paging";
export default function Home() {
const defaultKeyword = ["鳥", "犬", "猫"];
const randomKeyword =
defaultKeyword[Math.floor(Math.random() * defaultKeyword.length)];
const [keyword, setKeyword] = useState(randomKeyword); //指定キーワード
const [category, setCategory] = useState(""); //指定カテゴリ
const [page, setPage] = useState(1); //現在のページ
const [resultsPerPage, setResultsPerPage] = useState(10); //1ページあたりのitem数
const [items, setItems] = useState([]); //アイテムの配列
const [pageCount, setPageCount] = useState(""); //総ページ数
const options = {
params: {
keyword: keyword,
category: category,
page: page,
results_per_page: resultsPerPage,
},
};
let readMoreFlg = false;
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
const searchItems = (e) => {
e.preventDefault(); // リロードを止める
setPage(1);
options.params.page = 1;
getItems();
// scroll_to_top();
};
// Search
const categoryItems = (categorye) => {
// e.preventDefault(); // リロードを止める
setPage(1);
setCategory(categorye);
options.params.page = 1;
options.params.category = categorye;
getItems();
// scroll_to_top();
};
const reload = (e) => {
location.reload();
};
const scroll_to_top = () => {
window.scroll({ top: 0, behavior: "auto" });
};
// Pagination +
const pageIncrement = () => {
if (page < pageCount) {
const newPage = page + 1;
// setPage(newPage);
setPage((prevPage) => prevPage + 1);
options.params.page = newPage;
readMoreFlg = false;
getItems();
// scroll_to_top();
}
};
// Pagination -
const pageDecrement = () => {
if (page > 1) {
const newPage = page - 1;
// setPage(newPage);
setPage((prevPage) => prevPage - 1);
options.params.page = newPage;
readMoreFlg = false;
getItems();
// scroll_to_top();
}
};
const pageChange = (newPage) => {
setPage(newPage);
options.params.page = newPage;
readMoreFlg = false;
getItems();
};
return (
<div className={styles.zentai}>
<div className={styles.container}>
<Head>
<title>総合ショップ</title>
{/* <meta name="viewport" content="width=device-width,initial-scale=1.0" /> */}
{/* <meta name="viewport" content="viewport-fit=cover" /> */}
</Head>
<div id="page_top"></div>
<div className={styles.top}>
<Title reload={reload} />
<Form
category={category}
setKeyword={setKeyword}
setCategory={setCategory}
searchItems={searchItems}
keyword={keyword}
/>
{/* <div style={{ marginTop: "24px" }}> */}
</div>
<div className={styles.paginationT}>
<Paging
pageIncrement={pageIncrement}
pageDecrement={pageDecrement}
pageChange={pageChange}
page={page}
pageCount={pageCount}
/>
</div>
{/* <div className={styles.container2}> */}
{/* <Searchkey keyword={keyword} category={category} /> */}
<Sidebar
category={category}
setCategory={setCategory}
categoryItems={categoryItems}
/>
<Results items={items} keyword={keyword} category={category} />
<div className={styles.paginationB}>
<Paging
pageIncrement={pageIncrement}
pageDecrement={pageDecrement}
pageChange={pageChange}
page={page}
pageCount={pageCount}
/>
</div>
<Footer />
<a href="#page_top" className={styles.page_top_btn}>
トップへ戻る
</a>
</div>
</div>
);
}
components/paging.js
import styles from "../styles/Home.module.css";
const Paging = ({
pageIncrement,
pageDecrement,
pageChange,
page,
pageCount,
}) => {
let pageCount2 = pageCount;
if (pageCount2 > 1000) {
pageCount2 = 1000;
}
let haba = 2;
let startpage = page - haba;
if (startpage < 2) {
startpage = 2;
}
let endpage = page + haba;
if (endpage >= pageCount2) {
endpage = pageCount2 - 1;
}
const items = [];
if (page > 2) {
items.push(
<button className={styles.prevPageButton} onClick={() => pageDecrement()}>
前へ
</button>
);
}
if (pageCount2 > 1) {
items.push(
<button
className={page == 1 ? styles.pageButtonC : styles.pageButton}
onClick={() => pageChange(1)}
>
1
</button>
);
}
if (startpage >= 3) {
items.push(<span className={styles.pageSpan}>...</span>);
}
for (let i = startpage; i <= endpage; i++) {
items.push(
<button
className={i == page ? styles.pageButtonC : styles.pageButton}
onClick={() => pageChange(i)}
>
{i}
</button>
);
}
if (endpage <= pageCount2 - 2) {
items.push(<span className={styles.pageSpan}>...</span>);
}
if (pageCount2 > 1) {
items.push(
<button
className={page == pageCount2 ? styles.pageButtonC : styles.pageButton}
onClick={() => pageChange(pageCount2)}
>
{pageCount2}
</button>
);
}
if (page < pageCount2) {
items.push(
<button className={styles.nextPageButton} onClick={() => pageIncrement()}>
次へ
</button>
);
}
return (
<>
<div>{items}</div>
<div className={styles.pagination2}>
{page} / {pageCount > 1000 ? 1000 : pageCount} ページ
</div>
</>
);
};
export default Paging;
0