こんにちは!watnowの神宮です。
今回はmuiを用いたページネーションについて書かせてもらいます!
DBはsupbaseを使っています!
いくつか問題点はある実装だと思いますが、読んでもらえれば幸いです!
1.MUIをインストールする。
npm install @mui/material @emotion/react @emotion/styled
2.Pagenationをとりあえずつくる
"use client";
import Pagination from '@mui/material/Pagination';
const Pagenation: React.FC = ()=>{
return(
<Pagenation />
);
};
default export Pagenation
3.paginationをカスタマイズ
"use client";
import Pagination from '@mui/material/Pagination';
const Pagenation: React.FC = () =>{
return (
<Pagenation
count={8} //表示されるページ数が8になる
renderItem={(item)=>( //ページネーションの両サイドにある<,>を矢印に
<PaginationItem
{...item}
slots = {{
previous:()=> <div>←</div>,
next: ()=> <div>→</div>,
}}
/>
)}
/>
);
};
default export Pagenation
count
→ページネーションの総ページ数を決める
renderItem
→各ページアイテムをどのように表示するかを決める関数を
受け取って表示。
item
→各ページアイテムの情報を持っているオブジェクト
PaginationItem
→ページアイテムを表すコンポーネント
{...item}
→itemオブジェクトが持つプロパティをPagenationItemに渡している。
slots
→下記の~~~の部分を変えることで,ページネーションにある両端のボタンを変えることができる。
slots={{
previoust:()=> ~~
next: ()=> ~~~
}}
4.ページごとに表示されるものを変える。
ここからの僕の実装は問題ありです。
とりあえず実装したいんだ!という方の参考になれば幸いです!
まず、流れを説明します。
useStateで現在のページ数、画面に表示したいもののデータを保持
↓
ページネーションがクリックされたらページ数を+1
↓
ページ数が変わったら、データをDBから取ってきて、画面に表示したいもののデータを更新。
必要なstateを用意する
const [services, setServices] = useState<Service[]>([]); //表示したもののデータ
const [pageNum,setPageNum] = useState(1); //現在のページ数
const [totalPageNum,setTotalPageNum] = useState(0); //総ページ数
ページネーションがクリックされた時の処理を用意する
pagaNumを次に進めます!!
const scrollTop =()=>{
window.scrollTo({ top:0 });
};
const handlePageChange =(_: React.ChangeEvent<unknown>, nextPage:number)=>{
setPageNum(nextPage);
scrollTop();
console.log(nextPage);
}
return (
<Pagenation
//省略
onChange=(handlePage)
//省略
/>
);
_
→このアンダースコアは変数名。Js,Tsで使わない変数を_で表す
React.cahnageEvent
→ReactのChangeイベントを表す
unknow
→unknowはどのhtml要素から発生したのかわからない時に使う。
scrollTop()
→ページネーションをクリックしたときにページ上部へ移動するため。
_: React.ChangeEvent<unknown>,
nexPage: Paginationコンポーンネント勝手に計算して、次に表示するページを渡してくれます!
現在のpage数が変わった際の処理を用意
pageNumが変わったときに、ページ数に応じてデータを取得。
useEffect(()=>{
const start = (pageNum-1) * servicesPerPage;
const end = start + servicesPerPage - 1;
const fetchService = async () => { //ページ数に応じてデータを取得
const { data, error } = await supabase
.from("services")
.select("id,name,image")
.order("id", { ascending: true })
.range(start,end)
if (error) {
console.error("Error fetching events:", error);
} else {
console.log("Fetched data:", data);
setServices((data as Service[]) || []);
}
setLoading(false);
};
fetchService()
},[page])
start, end
→DBから取ってくるデータの最初の範囲を選ぶ。
.order("id", { ascending: true })
→idを使って昇順で取得
初回レンダリング時に表示されるデータ、ページに表示したいデータの総数を取得
useEffect(() => {
const start = (pageNum-1) * servicesPerPage;
const end = start + servicesPerPage - 1;
const fetchService = async () => {
const { data, error } = await supabase
.from("services")
.select("id,name,image")
.order("id", { ascending: true })
.range(start,end);
if (error) {
console.error("Error fetching events:", error);
} else {
console.log("Fetched data:", data);
setServices((data as Service[]) || []);
}
};
const fetchEventCount = async () => {
const { count, error:countError} = await supabase
.from("services")
.select('*',{count:'exact',head: true});
console.log("カウントしている",count);
if (countError) {
console.error("Error fetching event count",countError)
return;
}
setTotalServiceNum(count || 0);
}
fetchService();
fetchEventCount();
}, []);
最初の関数は同じものを2回書いています。よくないです!!
count:'exact'
→データ数を取得
head: true
→head:trueにすることでデータをとらずにデータ数のみ取得
5.ページネーションの表示ページ数を変える
<Pagination
className={styles.pageNation}
count={Math.ceil(totalServicesCount / servicesPerPage)}
onChange={handlePageChange}
renderItem={(item) => (
/>
Math.ceil
→jsのメソッドで小数点以下を切りあげる。
上記のコードで完成になります!!
最後に
次回ページネーションを作る機会があれば、よりスムーズに作れるようになったと思います。
このように一つずつ自分ができることを増やしていきたです。
ここまで読んでくださりありがとうございます。
アドバイスがあれば気軽におっしゃってください!!!