React Routerで/#/問題を解決!簡単3ステップでクリーンなURLを実現
React Router でブラウザの /#/
を停止する方法
BrowserRouter の basename プロップを使用する
最も簡単な方法は、BrowserRouter
コンポーネントの basename
プロップを使用することです。これは、ルーティングプレフィックスを設定し、#/
を含めないようにするものです。
import React from 'react';
import { BrowserRouter, Route } from 'react-router-dom';
const App = () => (
<BrowserRouter basename="/">
<div>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
</div>
</BrowserRouter>
);
export default App;
この方法の利点は、シンプルでわかりやすいことです。欠点は、アプリケーションが常にルートパスにあると想定されるため、一部の状況では意図しない動作を引き起こす可能性があることです。
withRouter HOC と history.replace を使用する
withRouter
高階コンポーネント (HOC) と history.replace
メソッドを使用して、#/
を手動で置き換えることができます。これは、より多くの制御が必要な場合に役立ちます。
import React from 'react';
import { withRouter } from 'react-router-dom';
const MyComponent = ({ history }) => {
useEffect(() => {
if (history.location.pathname === '/') {
history.replace('');
}
}, [history]);
return (
<div>
{/* コンポーネントのコンテンツ */}
</div>
);
};
export default withRouter(MyComponent);
この方法の利点は、#/
を置き換えるタイミングをより細かく制御できることです。欠点は、コードが少し複雑になることです。
Link コンポーネントの to プロップに ./ を使用する
Link
コンポーネントの to
プロップに ./
を使用して、相対パスを指定することもできます。これにより、#/
が自動的に削除されます。
import React from 'react';
import { Link } from 'react-router-dom';
const App = () => (
<div>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
</div>
);
export default App;
この方法の利点は、シンプルでわかりやすいことです。欠点は、すべてのリンクに ./
を明示的に追加する必要があることです。
カスタムフックを使用する
カスタムフックを使用して、useHistory
フックと useEffect
フックを組み合わせて、#/
をチェックして置き換えることができます。これは、再利用可能なロジックを作成したい場合に役立ちます。
import React, { useState, useEffect } from 'react';
import { useHistory } from 'react-router-dom';
const useReplaceSlash = () => {
const history = useHistory();
useEffect(() => {
if (history.location.pathname === '/') {
history.replace('');
}
}, [history]);
};
const MyComponent = () => {
useReplaceSlash();
return (
<div>
{/* コンポーネントのコンテンツ */}
</div>
);
};
export default MyComponent;
この方法の利点は、再利用可能なロジックを作成できることです。欠点は、コードが少し複雑になることです。
React Router でブラウザの /#/
を停止するには、いくつかの方法があります。最良のアプローチは、特定のニーズと要件によって異なります。
- 上記の例はすべて、
react-router-dom
v6 を使用しています。古いバージョンの場合は、API が異なる場合があります。
import React from 'react';
import { BrowserRouter, Route } from 'react-router-dom';
const App = () => (
<BrowserRouter basename="/">
<div>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
</div>
</BrowserRouter>
);
export default App;
import React from 'react';
import { withRouter } from 'react-router-dom';
const MyComponent = ({ history }) => {
useEffect(() => {
if (history.location.pathname === '/') {
history.replace('');
}
}, [history]);
return (
<div>
{/* コンポーネントのコンテンツ */}
</div>
);
};
export default withRouter(MyComponent);
import React from 'react';
import { Link } from 'react-router-dom';
const App = () => (
<div>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
</div>
);
export default App;
import React, { useState, useEffect } from 'react';
import { useHistory } from 'react-router-dom';
const useReplaceSlash = () => {
const history = useHistory();
useEffect(() => {
if (history.location.pathname === '/') {
history.replace('');
}
}, [history]);
};
const MyComponent = () => {
useReplaceSlash();
return (
<div>
{/* コンポーネントのコンテンツ */}
</div>
);
};
export default MyComponent;
react-router-dom
v6.8 以降では、新しい useLocation
フックを使用して現在の場所情報にアクセスできます。このフックを使用して、場所のパス名をチェックして、必要に応じて history.replace
を使用して /#/
を置き換えることができます。
import React from 'react';
import { useHistory } from 'react-router-dom';
const MyComponent = () => {
const history = useHistory();
const location = useLocation();
useEffect(() => {
if (location.pathname === '/') {
history.replace('');
}
}, [location]);
return (
<div>
{/* コンポーネントのコンテンツ */}
</div>
);
};
export default MyComponent;
onBeforeUnload イベントを使用する
onBeforeUnload
イベントを使用して、ユーザーがページから離れる前に /#/
を置き換えることができます。ただし、この方法は古く、すべてのブラウザでサポートされているわけではないことに注意してください。
import React, { useEffect } from 'react';
const MyComponent = () => {
useEffect(() => {
const handleBeforeUnload = (event) => {
if (window.location.pathname === '/') {
event.returnValue = '';
history.replace('');
return '';
}
};
window.addEventListener('beforeunload', handleBeforeUnload);
return () => {
window.removeEventListener('beforeunload', handleBeforeUnload);
};
}, []);
return (
<div>
{/* コンポーネントのコンテンツ */}
</div>
);
};
export default MyComponent;
サーバーサイドルーティングを使用する
Next.js などのサーバーサイドルーティングフレームワークを使用している場合は、サーバー側で /#/
をルート /
にリダイレクトするように設定できます。これにより、クライアント側で JavaScript を実行する必要がなくなります。
考慮事項
上記の方法を選択する際には、以下の点に注意する必要があります。
- ユーザーエクスペリエンス: ユーザーがブラウザの戻るボタンを使用した場合、予期しない動作が発生しないようにする必要があります。
- SEO: クライアント側で
/#/
を置き換える場合は、SEO に影響を与える可能性があることに注意してください。検索エンジンは、/#/
を異なる URL として認識する可能性があります。 - サポート: 使用する方法は、React Router のバージョンと使用しているブラウザによってサポートされていることを確認してください。
reactjs react-router