はじめに
表題通り、Reactでページ内遷移を実装します。
よくWebページで#値を元にページ内遷移ができるUIをどのように実装しているのだろうという興味のもと、今回実装してみました。
成果物
ソースコード
ディレクトリ構成
├── src
│ ├── App.tsx
│ ├── components
│ │ ├── ListCard.tsx
│ │ ├── ListContainer.tsx
│ │ ├── hooks.tsx
│ │ └── type.ts
│ ├── index.tsx
ソースコード
App.tsx
import React from 'react';
import { ListContainer } from './components/ListContainer'
function App() {
return (
<ListContainer />
);
}
export default App;
src/components/hooks.tsx
import { useEffect, useState } from "react"
import { ListItem } from "./type"
export const useCardScroll = () => {
const [list, setList] = useState<ListItem[]>([]);
useEffect(() => {
const items = Array.from({ length: 100 }, (_, index) => ({
id: `card${index + 1}`,
title: `タイトル${index + 1}`,
content: `コンテンツ${index + 1}`
}));
setList(items);
const scrollToCard = () => {
const hash = window.location.hash;
if (hash) {
const id = hash.replace('#', '');
const element = document.getElementById(id);
if (element) {
element.scrollIntoView();
}
}
};
scrollToCard(); // コンポーネントのマウント時にスクロール
window.addEventListener('hashchange', scrollToCard); // ハッシュ変更時にスクロール
return () => {
window.removeEventListener('hashchange', scrollToCard);
};
}, []);
return { list }
}
src/components/ListCard.tsx
import { Card, CardContent, Typography } from '@material-ui/core'
import React from 'react';
export interface ListItem {
id: string;
title: string;
content: string;
}
export const ListCard: React.FC<{ item: ListItem }> = ({ item }) => {
const handleClick = () => {
window.location.hash = item.id;
};
return (
<Card id={item.id} style={{ margin: '10px', width: '200px' }} onClick={handleClick}>
<CardContent>
<Typography variant="h6">{item.title}</Typography>
<Typography variant="body2">{item.content}</Typography>
</CardContent>
</Card>
);
};
src/components/ListContainer.tsx
import React from 'react';
import { ListItem } from './type'
import { ListCard } from './ListCard'
import { useCardScroll } from './hooks'
export const ListContainer: React.FC = () => {
const { list } = useCardScroll();
return (
<div>
{list.map((item: ListItem) => (
<ListCard key={item.id} item={item} />
))}
</div>
);
};
src/components/type.ts
export type ListItem = {
id: string;
title: string;
content: string;
}