今日は高度なReact Router テクニックを皆さんと共有できることをとても楽しみにしています。 React Router は、 Reactアプリケーションで動的でスムーズなナビゲーションを作成できる素晴らしいツールです。
これは基本的なルーティングのニーズによく使用されますが、ルーティング能力をまったく新しいレベルに引き上げることができる、あまり知られていないテクニックがいくつかあります。
今日は、私が時間をかけて見つけた私のお気に入りのいくつかを共有します。
useNavigate
フックとuseLocation
フックを使用します。
この記事を読み終える頃には、これらの高度な React Router テクニックをしっかりと理解し、自信を持って自分のプロジェクトに適用できるようになっているでしょう。
それでは、早速本題に取り掛かり、一緒にルーティング スキルを向上させましょう。
準備はできたか?始めましょう!
より大きなプロジェクトに取り組むときは、見つからないルートに注意することが不可欠です。これらのルートは、サーバー上でドキュメントが見つからない場合にHTTP ステータス コード404 を返すため、多くの場合404 ルートと呼ばれます。
ちなみに、猫好きの方はhttp.catをチェックしてみるのも楽しいかもしれません。
次に、ブラウザ内の現在の URL に一致する他のルートがない場合にトリガーされる特別なルートの作成に移りましょう。
import {BrowserRouter, Routes, Route} from "react-router-dom"; function App() { return <BrowserRouter> <Routes> <Route path="/" element={<p>Landing page</p>}></Route> <Route path="/products" element={<p>Products page</p>}></Route> <Route path="*" element={<p>404 page</p>}></Route> </Routes> </BrowserRouter> }
プライマリ ページ/
にアクセスすると、ユーザーはランディング ページにリダイレクトされます。 /products
ページに移動すると、Products ページに移動します。ただし、特定のルートに対応しない他のリンクにアクセスすると、404 ページが表示されます。
この動作の背後にある理由は、パス プロパティが*
に設定されている、404 ページ用の特殊な<Route>
の実装です。この構成により、他に一致するルートがない場合に、React Router がこのルートを排他的に利用するようになります。 404 Route の具体的な配置は重要ではなく、その不可欠なコンポーネントとして<Routes>...</Routes>
セクション内のどこにでも配置できます。
アプリがルートを実際に利用できるもう 1 つの方法は、メニュー内で現在アクティブなページを強調表示することです。
ホーム - このリンクにより、ユーザーはメイン ページ/
に移動します。
About - このリンクにより、ユーザーは about ページ/about
に移動します。
React Router を使用すると、ユーザーが/about
ルート上にいるときにAbout
リンクを自動的にハイライト表示できるようになります。同様に、ユーザーが/
ルート上にいるときにホーム リンクを強調表示できます。最も良い点は、複雑な条件を必要とせずにこれを実現できることです。
import {NavLink} from "react-router-dom"; function getClassName({isActive}) { if (isActive) { return "active"; // CSS class } } function App() { return <ul> <li> <NavLink to="/" className={getClassName}>Home</NavLink> </li> <li> <NavLink to="/about" className={getClassName}>About</NavLink> </li> </ul> }
上記のコードは、 active
クラスを機能させるためにいくつかの CSS を必要とします。したがって、現在アクティブなページのメニュー リンクを太字で目立つようにすることで、機能を強化できます。
.active { font-weight: bold; }
NavLink
要素のclassName
属性には、単なる文字列ではなく関数を受け入れる柔軟性があります。関数を使用することに決めた場合、関数にはパラメータとしてオブジェクトが与えられ、このオブジェクトにはisActive
プロパティがすでに設定されています。関数内でこのプロパティに簡単にアクセスするには、パラメーターに{isActive}
を含めて構造化を使用します。
次に、 isActive
正しい値を保持しているかどうかの検証に進みます。その場合は、 CSSクラス名active
を返します。
React Router の現在のパスがNavLink
コンポーネントのto
属性と一致する場合、 isActive
関数はブール値に評価されます。
その結果、React Router はactive
クラスを対応する<NavLink />
要素にシームレスに組み込み、それが現在アクティブなルートであることを示します。
より短いアプローチを希望する場合は、三項演算子を使用して上記のコードをリファクタリングできます。この演算子は、次の形式を使用して if/else ステートメントを置き換える方法を提供しますcondition ? truthy expression : falsy expression
。
三項演算子はコードが読みにくくなることが多いため、実際にはあまり使用しません。ただし、この場合は使用しても問題ありません。
function getClassName({isActive}) { if (isActive) { return "active"; } else { return ""; } }
function getClassName({isActive}) { return isActive ? "active" : ""; }
return ステートメントが三項演算子の外側に配置されていることを確認するだけで済みます。 isActive
条件が true の場合、 ?
以降の式は"active"
で実行されます。それ以外の場合は、 :
の後の式が""
実行されます。
これで、 getClassName
と呼ばれる別の関数定義の必要性を排除できます。代わりに、次のようなアロー関数を使用できます: ({isActive}) => isActive ? "active" : ""
。
この変更がわかりにくい場合は、以前と同様に別の関数を使用し続けることができます。
import {NavLink} from "react-router-dom"; function App() { return <ul> <li> <NavLink to="/" className={({isActive}) => isActive ? "active" : ""}>Home</NavLink> </li> <li> <NavLink to="/about" className={({isActive}) => isActive ? "active" : ""}>About</NavLink> </li> </ul> }
ああ、あなたの意見はよくわかります。
ソジンさん、DRY原則を破ってしまいましたよね?
これはほんの一例です。気を引き締める必要はありません 😀
すでにお気づきかもしれませんが、私はいつもの友人であるLink
の代わりにNavLink
を使用しています。でも心配しないでください、その理由を説明しましょう。 <Link />
コンポーネントでは、 className
プロパティの関数定義を使用できません。そうですね、驚くかもしれませんが、 <Link />
を操作するときはまさにそのような感じです。
私がこれまでに見たよくある間違いの 1 つは、若手 React 開発者が<Link />
コンポーネントのclassName
プロパティで関数定義を使用しようとしたことですが、これはまったく機能しません。
ご興味があれば、このトピックについて記事を書きます。コメント欄でお知らせください!
特定の状況では、React アプリケーション内のページをプログラムで再配置する必要がある場合があります。たとえば、訪問者を特定のページにリダイレクトするには、リクエストを送信して応答を待つことができます。
/dashboard
にリダイレクトします。
これには、 useNavigate()
フックを使用する必要があります。このフックは、プログラムでユーザーを新しいルートにリダイレクトするために使用できる関数を返します。
ご覧ください:
import React, {useEffect} from "react"; import {useNavigate} from "react-router-dom"; function HelpPage() { const navigate = useNavigate(); useEffect(() => { const isLoggedIn = window.localStorage.getItem("isLoggedIn"); if (!isLoggedIn) { navigate("/login"); } }, []); return <h2>Help page</h2>; }
この例では、 localStorage にキーisLoggedIn
に割り当てられた値があるかどうかを確認しています。そうでない場合は、 navigate("/login")
関数を使用してユーザーを/login
ページにリダイレクトします。
これを機能させるには、 <BrowserRouter />
コンポーネント内にネストされているコンポーネント内でuseNavigate()
フックを使用することを忘れないでください。そうしないと、正しく機能しません。
たとえば、次の例は機能しません。
import React from "react"; import {BrowserRouter, useNavigate} from "react-router-dom"; function App() { // ❌ This breaks because the component was not wrapped by BrowserRouter, but its children are. const history = useNavigate(); return <BrowserRouter> {/* ... */} </BrowserRouter>; }
App()
コンポーネント内でuseNavigate()
フックを使用しようとすると、少し問題が発生する可能性があります。これは、 App()
コンポーネントを<BrowserRouter />
でラップしない限り機能しないためです。
でも心配しないでください。
良いニュースは、App 内のすべての子コンポーネントが<BrowserRouter />
によって自動的にラップされるため、これらの子コンポーネントでuseNavigate()
を問題なく使用できることです。
ただし、本当に<App />
コンポーネント自体でuseNavigate()
を使用する必要がある場合は、簡単な解決策があります。 <App />
をラップする親コンポーネントを作成し、その親コンポーネント内に<BrowserRouter />
を移動するだけです。これを完了したら、 <App />
コンポーネントでuseNavigate()
を思う存分使用できるようになります 💗
Web サイトをアクセシブルにする場合、リンクの構造に注意を払うことが重要です。これを確実に行うには、他のメソッドではなく<Link />
要素を使用することをお勧めします。
なぜ?
これらの要素は、アクセシビリティ機能で知られる<a>
タグとして自動的にレンダリングされます。
さて、ここでフレンドリーなヒントを紹介します。通常の<Link />
要素をuseNavigate()
が提供する.push()
メソッドに置き換えることは避けてください。このメソッドは<Link />
要素を使用できない場合にのみ使用してください。
通常、これは、 fetch()
操作の結果など、特定のロジックに基づいてプログラムでユーザーをリダイレクトする必要がある場合です。
React Router が新しいアドレスに移動するたびにコードを実行したい場合はどうすればよいでしょうか?
useLocation
フックを使用すると、これを簡単に実現できます。詳細に入る前に、これが役立ついくつかのシナリオを検討してみましょう。最も一般的な使用例の 1 つは、Google Analytics などの分析サービスにページビューイベントを送信することです。
ただし、Google アナリティクス 4 ではこれが自動的に処理されるため、必ずしも自分で実装する必要はないことに注意してください。
それでも、 useLocation
フックについて学ぶことは、他の用途が見つかる可能性があるため、依然として価値があります。たとえば、これを使用して他のライブラリや分析サービスと統合したり、訪問ルートに基づいて特定のアクションを実行したりできます。
可能性は無限大!
useLocation
フックは、現在使用されているルートに関する情報を提供するため、非常に便利です。
useLocation フックの使用方法に関するわかりやすいガイドは次のとおりです。
import {BrowserRouter, Routes, Route, useLocation} from "react-router-dom"; import {createRoot} from "react-dom/client"; function App() { const location = useLocation(); console.log(location.pathname); return <Routes> {/* routes here... */} </Routes> } createRoot(document.querySelector("#react-root")).render(<BrowserRouter><App /></BrowserRouter>);
これで、location 変数を介してルート情報にアクセスできるようになりました。これは、現在のpathname
を含むオブジェクトです。
ユーザーが現在どのルートを参照しているかを確認するには、 location.pathname
使用するだけです。 /
、 /about
、または設定したその他のルートのようなものが表示されます。
useNavigate
フックと同様に、 <BrowserRouter />
でラップされたコンポーネント内でコードを実行することが重要であることに注意してください。そうしないと、 useLocation
フックはその魔法を発揮できません。
場所が変更された場合、 useLocation
フックを使用して React Router の現在の URL パスにアクセスできます。コードをuseEffect
フックでラップし、依存関係をlocation
に設定すると、新しい URL へのナビゲーションがあるたびに特定のコード部分を実行できます。
import React, {useEffect} from "react"; import {BrowserRouter, Routes, Route, useLocation} from "react-router-dom"; import {createRoot} from "react-dom/client"; function App() { const location = useLocation(); // run a piece of code on location change useEffect(() => { console.log(location.pathname); // send it to analytic, or do some conditional logic here }, [location]); return <Routes> {/* routes here... */} </Routes> } createRoot(document.querySelector("#react-root")).render(<BrowserRouter><App /></BrowserRouter>);
ユーザーがナビゲーション中に新しいルートに移動するたびに、 useEffect
フック内のコードが実行され、その処理が行われます。これは基本的に、場所オブジェクトに変更があるたびに特定のコードが確実に実行されるようにする方法です。
結論として、この記事では React Router についてより深く理解することができました。ただし、ここで説明したすべての機能を使用できるわけではありません。それでも、あなたがそれらを認識していることは素晴らしいことです。将来、同様の機能を組み込む必要がある場合でも、どこを調べればよいかがわかります。したがって、簡単に参照できるように、必ずこの投稿を保存またはブックマークしてください。ご質問がある場合、またはさらにサポートが必要な場合は、お気軽に Twitter までご連絡ください。私は助けに来ました!