記事ディレクトリ
ルーティングの概要
概要
React Router は、次の 3 つの異なるパッケージで npm に公開されています。
- react-router: コンポーネント、フックなど、多くの機能を提供するルーティングのコア ライブラリ。
- react-router-dom: react-router のすべてのコンテンツを含み、DOM 専用のコンポーネントをいくつか追加します
<BrowserRouter>
。 - react-router-native: react-router のすべてのコンテンツを含め、次のような ReactNative 専用の API をいくつか追加します
<NativeRouter>
。
バラエティ
React Router 5.x バージョンと比べて何が変わったのですか?
-
組み込みコンポーネントの変更: 削除
<Switch/>
、追加<Routes/>
など。 -
構文の変更: etc
component={About}
に変更されました。element={<About/>}
-
複数のフックを追加:
useParams
、useNavigate
などuseMatch
。 -
公式の推奨事項は、機能コンポーネントを使用することです
書類
公式サイトアドレス:https://reactrouter.com/
ルーティング コンポーネント
ブラウザルーター
<BrowserRouter>
アプリケーション全体をラップするために使用されます。
import React from "react";
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from "react-router-dom";
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<BrowserRouter>
{/* 整体结构(通常为App组件) */}
</BrowserRouter>
);
ハッシュルーター
機能は<BrowserRouter>
同じですが、<HashRouter>
アドレスバーのハッシュ値が変更されます。
備考:バージョン 6.x の<HashRouter>
,の使用法は、 <BrowserRouter>
5.x の場合と同じです。
ルートとルート
Routes はルーティング マネージャーを作成するためのもので、Route はルーティング オブジェクトを作成するためのものです。
-
以前のものはバージョン v6 で削除され
<Switch>
、新しい置換が導入されました:<Routes>
. -
<Routes>
と一緒に使用する<Route>
には、<Routes>
パッケージ化する必要があります<Route>
。 -
<Route>
パスが現在の URL と一致する場合に、対応するコンポーネントをレンダリングする if ステートメントに相当します。 -
<Route caseSensitive>
この属性は、大文字と小文字を区別して一致させるかどうかを指定するために使用されます (デフォルトは false)。 -
URL が変更されると、
<Routes>
そのすべての子要素が調べられて<Route>
最適な一致が検出され、コンポーネントがレンダリングされます。 -
<Route>
ネストすることもでき、「ルーティング テーブル」の構成に使用できますuseRoutes()
が、<Outlet>
コンポーネント。
<Routes>
{/* path定义路径,可以省略path前的/;element定义当前路径对应的组件 */}
<Route path='/' element={<Home />} />
{/*
路由嵌套:路由嵌套要写在路由配置页,渲染嵌套的路由组件的位置使用Outlet
friend 是一级路由,路径为 /friend
chat是二级路由,对应路径为 /friend/chat/张三
*/}
<Route path='friend' element={<Friends />} />
<Route path='chat/:name' element={<Chat />} />
</Route>
<Route path='setting' element={<Settings />} />
{/* Route也可以不写element属性, 这时就是用于展示嵌套的路由,所对应的路径是/users/login */}
<Route path="user">
<Route path="login" element={<Login />} />
</Route>
{/* 当没有其他路由匹配该URL时,你可以使用path="*"渲染一个"未找到"的路由。这条路由将匹配任何URL,但优先级最低,因此路由器只有在没有其他路由匹配的情况下才会选择它 */}
<Route path='*' element={<NotFound />} />
</Routes>
リンク
<Link>
ネットワーク要求 (ルーティング リンク) を送信せずに URL を変更します。
注:<Link>
外側をラップ<BrowserRouter>
または<HashRouter>
ラップする必要があります。
import { Link } from "react-router-dom";
const App = () => {
const [items, setItems] = useState([
{ path: '/', title: '首页', conponent: Home },
{ path: '/friend', title: '好友', conponent: Friends },
{ path: '/setting', title: '设置', conponent: Settings },
]);
return (
<div className='app'>
<nav className='nav'>
<div className='w'>
{items.map(item => (
<Link to={item.path} key={item.path}>
{item.title}
</Link>
))}
</div>
</nav>
</div>
);
};
ナビリンク
<NavLink>
コンポーネントと同様に<Link>
、ナビゲーションの「ハイライト」効果を実現できます。
-
NavLink组件
と の機能は同じですが、現在一致しているルートかどうかをLink组件
判断できる点が異なりますto属性
-
NavLink组件
または、関数を受け取り、関数がパラメーターを受け取り、パラメーターに応じてスタイルを調整style
したり、強調表示の状態を処理したりできます. NavLink のデフォルトのクラス名はアクティブであり、クラスをカスタマイズすることで強調表示を実現できます.名前またはスタイル:className
isActive
-
カスタムクラス名
<NavLink className={({ isActive }) => (isActive ? 'active' : '')} to={item.path} key={item.path}>
{item.title}
</NavLink>
- カスタムスタイル
<NavLink style={({ isActive }) => ({backgroundColor: isActive ? 'lightblue': ''})} to={item.path} key={item.path}>
{item.title}
</NavLink>
デフォルトでは、ホームのサブコンポーネントが正常に一致すると、ホームのナビゲーションも強調表示されます。
NavLink に end 属性を追加すると、Home のサブコンポーネントが正常に一致すると、Home のナビゲーションが強調表示されなくなります。
<NavLink to="home" end >home</NavLink>
ナビゲート
<Navigate>
コンポーネントがレンダリングされるたびに、パスが変更され、ビューが切り替えられます (リダイレクトされます)。
<Navigate>
のプロパティreplace
は、ジャンプ モード (プッシュまたは置換、デフォルトはプッシュ) を制御するために使用されます。
import { useState } from 'react';
import { Navigate } from 'react-router-dom';
const Home = props => {
const [show, setShow] = useState(false);
return (
<div id='home' className='w'>
<h1>首页</h1>
{/* 根据show的值决定是否切换视图 */}
{show && <Navigate to='/setting' replace={true} />}
<button onClick={() => setShow(true)}>按钮</button>
</div>
);
};
出口
ネストが生成されると<Route>
、それに対応する後続のサブルートがレンダリングされます。
import { useState } from 'react';
import { NavLink, Outlet } from 'react-router-dom';
const Friends = props => {
const [items, setItems] = useState([
{ name: 'Tom', id: 10 },
{ name: 'Lily', id: 11 },
{ name: 'Lucy', id: 12 },
]);
return (
<div id='home' className='w'>
<nav className='nav-home'>
{items.map(item => {
return (
<NavLink className={({ isActive }) => (isActive ? 'active link' : 'link')} to={'/friend/chat/' + item.name} key={item.id}>
{item.name}
</NavLink>
);
})}
</nav>
{/* Outlet 渲染子路由组件 */}
<Outlet className='child'></Outlet>
</div>
);
};
ルーティング フック
useRoutes()
機能:ルーティング テーブルに従って動的に<Routes>
作成します<Route>
。その役割は、ルートを動的に構成することであり、ルートの配列を受け取り、一致したルートを使用して対応するコンポーネントをレンダリングします。
useRoutes()
と機能的に同等です<Routes>
が、要素の代わりに JavaScript オブジェクトを使用してルートを定義します。これらのオブジェクトには、<Route>
コンポーネント。
useRoutes()
の戻り値は、ルーティング ツリーのレンダリングに使用できる有効な React 要素です。
//路由表配置:src/routes/index.jsx
import { Navigate } from 'react-router-dom';
import Home from '../views/Home';
import Friend from '../views/Friend';
import Setting from '../views/Setting';
import NotFound from '../views/NotFound';
import Chat from '../views/Chat';
const routes = [
{ path: '/', element: <Navigate to='/home' /> },
{ path: '/home', element: <Home /> },
{
path: '/friend',
element: <Friend />,
children: [{ path: 'chat/:name', element: <Chat /> }],
},
{ path: '/setting', element: <Setting /> },
{ path: '*', element: <NotFound /> },
];
export default routes;
// App.jsx
import { useState } from 'react';
import { NavLink, useRoutes } from 'react-router-dom';
import routes from './routes';
const App = () => {
// 根据路由表生成对应的路由规则
const ElementRouter = useRoutes(routes)
const [items] = useState([
{ path: '/home', title: '首页' },
{ path: '/friend', title: '好友' },
{ path: '/setting', title: '设置' },
]);
return (
<div className='app'>
<nav className='nav'>
<div className='w'>
{items.map(item => (
<NavLink className={({ isActive }) => (isActive ? 'active' : '')} to={item.path} key={item.path}>
{item.title}
</NavLink>
))}
</div>
</nav>
{/* 注册路由 */}
{ElementRouter}
</div>
);
};
useNavigate()
Role: プログラム ナビゲーションの実装に使用される関数を返します。
import { useNavigate } from 'react-router-dom';
function Chat(props) {
const navigate = useNavigate();
const goBack = () => {
// 第一种使用方式:传入数值进行前进或后退,类似 history.go()方法
// navigate(-1);
// 第二种使用方式:指定具体的路径
navigate('/friend', {
replace: false,
state: { a: 1, b: 2 },
});
};
return (
<div id="chat" className="w">
<h2>chat页面 </h2>
<button onClick={goBack}>返回</button>
</div>
);
}
useParams()
機能:params
現在一致しているルートのパラメーターを返します。
import { useParams, useNavigate, useLocation } from 'react-router-dom';
function Chat(props) {
// 获取路径参数
const params = useParams();
return (
<div id='chat' className='w'>
<h2>chat页面</h2>
<p>params.name: {params.name}</p>
</div>
);
}
const App = () => {
return (
<div className='app'>
<Routes>
<Route path='chat/:name' element={<Chat />} />
</Routes>
</div>
);
};
useLocation()
機能: 現在の位置情報を取得し、 5.x のルーティング コンポーネントのlocation
プロパティを比較します。
import { useLocation } from 'react-router-dom';
function Friend(props) {
// 路由位置信息
const location = useLocation();
console.log(location);
// {
// hash: "",
// key: "1nw4p3qf",
// pathname: "/friend",
// search: "?name=张三&age=18",
// state: {a: 1, b: 2},
// }
return (
<div id='friend' className='w'>
<h2>friend页面</h2>
</div>
);
}
useSearchParams()
役割: 現在の場所の URL のクエリ文字列を読み取って変更するために使用されます。
現在の検索パラメーターと検索を更新する関数の 2 つの値を含む配列を返します。
function Chat(props) {
const [search, setSearch] = useSearchParams();
const name = search.get('name');
const age = search.get('age');
return (
<div id='chat' className='w'>
<h2>chat页面</h2>
<button onClick={() => setSearch('name=张三&age=18')}>点击更新一下收到的search参数</button>
<p> name={name} </p>
<p> age={age} </p>
</div>
);
}
useMatch()
機能: 現在一致している情報を返し、 5.x のルーティング コンポーネントのmatch
プロパティを比較します。
<Route path="/friend/chat/:name" element={<Chat />}/>
<NavLink to="/friend/chat/Tom">好友</NavLink>
function Chat(props) {
const match = useMatch('/friend/chat/:name');
console.log(match);
// {
// params: { name: 'Tom' },
// pathname: "/friend/chat/Tom",
// pathnameBase: "/friend/chat/Tom",
// pattern: {path: '/friend/chat/:name', caseSensitive: false, end: true},
// }
return (
<div id='chat' className='w'>
<h2>chat页面</h2>
</div>
);
}
useInRouterContext()
役割: コンポーネント<Router>
がuseInRouterContext
フックのコンテキストでレンダリングされる場合は true を返し、それ以外の場合は false を返します。
useNavigationType()
機能: 現在のナビゲーション タイプ (ユーザーがどのようにして現在のページに到達したか) を返します。
戻り値: POP
, PUSH
, REPLACE
.
備考:POP
これは、ルーティング コンポーネントがブラウザーで直接開かれる (ページを更新する) ことを意味します。
useOutlet()
役割: 現在のコンポーネントでレンダリングされるネストされたルートをレンダリングするために使用されます。
const result = useOutlet()
console.log(result)
// 如果嵌套路由没有挂载,则result为null
// 如果嵌套路由已经挂载,则展示嵌套的路由对象
useResolvedPath()
機能: URL 値を指定すると、パス、検索、ハッシュの値を解析します。
ルーティング手順
ステップ 1: インストール
react-router-dom はブラウザ側の react-router ライブラリをベースにしたライブラリなので、これをインストールすれば手動で react-router をインストールする必要はありません
npm install react-router-dom
ステップ 2: ルーターを接続する
アプリをブラウザの URL にリンクします。BrowserRouter を App にラップする
// main.jsx
import { BrowserRouter } from 'react-router-dom';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<BrowserRouter>
<App />
</BrowserRouter>
);
ステップ 2: ルーティング テーブルの構成
//路由表配置:src/routes/index.jsx
import { Navigate } from 'react-router-dom';
import Home from '../views/Home';
import Friend from '../views/Friend';
import Setting from '../views/Setting';
import NotFound from '../views/NotFound';
import Chat from '../views/Chat';
const routes = [
// Navigate 重定向
{ path: '/', element: <Navigate to='/home' /> },
{ path: '/home', element: <Home /> },
{
path: '/friend',
element: <Friend />,
children: [{ path: 'chat/:name', element: <Chat /> }],
},
{ path: '/setting', element: <Setting /> },
{ path: '*', element: <NotFound /> },
];
export default routes;
手順 4: ルーティングを登録し、ルーティング リンクを構成する
にルートを登録しsrc/App.jsx
、リンクとグローバル ナビゲーションを追加します。
// App.jsx
import { useState } from 'react';
import './App.css';
import { NavLink, useRoutes } from 'react-router-dom';
import routes from './routes';
const App = () => {
// 根据路由表生成对应的路由规则
const ElementRouter = useRoutes(routes);
const [items] = useState([
{ path: '/home', title: '首页' },
{ path: '/friend', title: '好友' },
{ path: '/setting', title: '设置' },
]);
return (
<div className='app'>
<nav className='nav'>
<div className='w'>
{/* 路由链接 */}
{items.map(item => (
<NavLink className={({ isActive }) => (isActive ? 'active' : '')} to={item.path} key={item.path}>
{item.title}
</NavLink>
))}
</div>
</nav>
{/* 注册路由 */}
{ElementRouter}
</div>
);
};
export default App;
ステップ 5: ルーティング コンポーネントを作成する
ルーティング コンポーネントは、src ディレクトリのビュー ファイルまたはページ ファイルに配置されます。
コンポーネントを使用してルーティングを構成する
import { NavLink, Route, Routes } from 'react-router-dom';
import Chat from './views/Chat';
import Friend from './views/Friend';
import Home from './views/Home';
import NotFound from './views/NotFound';
import Setting from './views/Setting';
const App = () => {
const items = [
{ path: '/', title: '首页' },
{ path: '/friend', title: '好友' },
{ path: '/setting', title: '设置' },
];
return (
<div className='app'>
<nav className='nav'>
<div className='w'>
{items.map(item => (
<NavLink className={({ isActive }) => (isActive ? 'active' : '')} to={item.path} key={item.path}>
{item.title}
</NavLink>
))}
</div>
</nav>
<Routes>
<Route path='/' element={<Home />} />
<Route path='friend' element={<Friend />}>
<Route path='chat/:name' element={<Chat />} />
</Route>
<Route path='setting' element={<Setting />} />
<Route path='*' element={<NotFound />} />
</Routes>
</div>
);
};
export default App;
デフォルトルート
デフォルト ルートは index 属性を使用して実装されます。
インデックス ルートと他のルートの違いは、パス属性がなく、親ルートと同じパスを共有することです。
- インデックス ルートは親ルートの出口でレンダリングされ、ルート アドレスは親ルートと同じです
- 親ルートが一致し、他の子ルートが一致しない場合、インデックス ルートが一致します。
- インデックス ルートは、親ノードのデフォルトの子ノードです
- インデックス ルートは、ユーザーがまだナビゲーションのリンクをクリックしていないときにレンダリングされます
const routes = [
{
path: '/setting',
element: <Setting />,
children: [
{ index: true, element: <Other1 /> },
{ path: 'other1', element: <Other1 /> },
{ path: 'other2', element: <Other2 /> },
],
},
];
import { Link,Outlet } from "react-router-dom";
const Settings = props => {
return (
<div id='settings' className='w'>
<h1>设置</h1>
<Link to='/setting/other1'>选项1</Link>
<Link to='/setting/other2'>选项2</Link>
<Outlet className='child'></Outlet>
</div>
);
};
export default Settings;
- パス
/setting
が の、Setting コンポーネントの Outlet にOther1
コンポーネントが表示されます - パス
/setting/other1
が の、Setting コンポーネントの Outlet にOther1
コンポーネントが表示されます - パス
/setting/other2
が の、Setting コンポーネントの Outlet にOther2
コンポーネントが表示されます
経路監視
import { useLocation } from 'react-router-dom';
// 监听路由的变化
const location = useLocation();
useEffect(() => {
console.log('进入:', location.pathname);
return () => {
console.log('离开:', location.pathname);
};
});
ルーティング パラメータ
params パラメータ
反応ルーティングは動的ルーティングをサポートします
// 路由表
const routes = [
{
path: 'chat/:name',
element:<Chat/>,
},
];
<Link to='/chat/张三'>张三</Link>
useParams を使用してパラメーターを取得する
import { useParams } from 'react-router-dom';
// 获取路径参数
const params = useParams();
params // {name: '张三'}
検索パラメータ
// 路由表
const routes = [
{
path: 'chat',
element: <Chat/>,
},
];
<Link to='/chat/?name=张三'>张三</Link>
useSearchParams を使用してパラメーターを取得する
import { useSearchParams } from 'react-router-dom';
const [search, setSearch] = useSearchParams();
const name = search.get('name'); // 张三
または useLocation を使用します
import { useLocation } from 'react-router-dom';
import qs from "query-string";
const { search } = useLocation();
console.log(qs.parse(location.search)); // {name: '张三'}
備考: useLocation によって取得される検索は、urlencoded でエンコードされた文字列 (例: ?age=20&name=zhangsan) であり、クエリ文字列を使用してオブジェクトに解析する必要があります。
状態属性
リンクの状態プロパティを介してパラメーターを渡す
// 路由表
const routes = [
{
path: 'chat',
element: <Chat/>,
},
];
<Link to='/chat' state={ {name:'张三'} }>张三</Link>
useLocation を使用してパラメーターを取得する
import { useLocation } from 'react-router-dom';
let { state } = useLocation();
state // {name: '张三'}
プログラムによるナビゲーション
useNavigate を使用したプログラムによるナビゲーション
import { useNavigate } from "react-router-dom";
export default function Demo() {
const navigate = useNavigate();
//...
}
プッシュナビゲーション
- プッシュ ジャンプ + キャリー パラメータ パラメータ
navigate(`/child/${id}/${title}`);
- プッシュジャンプ+キャリー検索パラメータ
navigate(`/child?id=${id}&title=${title}`);
- プッシュジャンプ+キャリー状態パラメータ
navigate("/child", { state: { id, title }});
ナビゲーションを置き換える
- ジャンプ+キャリーパラメータパラメータを置き換えます
navigate(`/child/${id}/${title}`,{replace: true});
- ジャンプ + キャリ検索パラメータを置換
navigate(`/b/child?id=${id}&title=${title}`,{replace: true});
- ジャンプ+キャリー状態パラメータを置換
navigate("/child", { state: { id, title },replace: true});
遅延読み込みのルーティング
- React は React.lazy と import() を使用して、レンダリング中に動的な読み込みを実現します
- サスペンスを使用して、リソースが非同期で読み込まれるときにページをどのように表示するかという問題に対処します
- lazy() API を介して遅延読み込みを必要とするコンポーネントを動的にインポートする
- インポートされたコンポーネントは現在、デフォルトの形式でのエクスポートのみをサポートしています
- Suspense は、読み込みのために遅延読み込みされたコンポーネントをラップし、読み込み効果を実現するためにフォールバックを設定できます
- React.lazy を Router と組み合わせて、モジュールを遅延ロードすることができます。
React.Suspense
でReact.lazy
達成する
React.suspense
遅延読み込みルーティングを実装するための読み込みポケット
<Suspense fallback={<Loading />}>
<SomeComponent />
</Suspense>
fallback
パラメーターは、react コンポーネントまたは dom 要素で渡すことができます。次に例を示します。<div>Loading...</div>
- 注:
React.suspense
遅延ロードされたルートだけでなく、遅延ロードされたすべてのコンポーネントについて、遅延ロードがある限り、それらは外部パッケージReact.suspense
ングloading
または他の方法で実装できます。占位dom
React.lazy
ルートの遅延読み込みを実装するためにコンポーネント パスをラップするために使用されます
const LazyDemoPage = lazy(() => import("@views/DemoPage"));
- 注:
React.lazy
現在、デフォルトのエクスポートのみがサポートされています
場合:
//路由表配置:src/routes/index.jsx
import { lazy, Suspense } from 'react';
const Chat = lazy(() => import('@/views/Chat'));
const Friend = lazy(() => import('@/views/Friend'));
const Home = lazy(() => import('@/views/Home'));
const Setting = lazy(() => import('@/views/Setting'));
const NotFound = lazy(() => import('@/views/NotFound'));
const LoadingTip = Element => (
<Suspense fallback={<div>loading...</div>}>
<Element />
</Suspense>
);
const routes = [
{ path: '/', element: LoadingTip(Home) },
{
path: '/friend',
element: LoadingTip(Friend),
children: [
{
path: 'chat/:name',
element: LoadingTip(Chat),
},
],
},
{ path: '/setting', element: LoadingTip(Setting) },
{ path: '*', element: LoadingTip(NotFound) },
];
export default routes;
経路遮断
ルーティング テーブル
//路由表配置:src/routes/index.jsx
import { lazy, Suspense } from 'react';
const Chat = lazy(() => import('@/views/Chat'));
const Friend = lazy(() => import('@/views/Friend'));
const Home = lazy(() => import('@/views/Home'));
const Login = lazy(() => import('@/views/Login'));
const NotFound = lazy(() => import('@/views/NotFound'));
const LoadingTip = Element => (
<Suspense fallback={<div>loading...</div>}>
<Element />
</Suspense>
);
const routes = [
{
path: '/',
element: LoadingTip(Home),
meta: {
title: '首页',
auth: false,
menu: true,
},
},
{
path: '/friend',
element: LoadingTip(Friend),
meta: {
title: '好友',
auth: true,
menu: true,
},
children: [
{
path: 'chat/:name?',
element: LoadingTip(Chat),
meta: {
title: '聊天',
auth: true,
menu: true,
},
},
],
},
{
path: '/login',
element: LoadingTip(Login),
meta: {
title: '登录',
auth: false,
menu: true,
},
},
{
path: '*',
element: LoadingTip(NotFound),
meta: {
title: '404',
auth: false,
menu: false,
},
},
];
export default routes;
インターセプト機能
//路由表配置:src/routes/routerBefore.jsx
import { Navigate, useLocation, useRoutes } from 'react-router-dom';
import routes from './index';
// 拦截组件
const RouterBeforeEach = props => {
if (props?.route?.meta?.title) {
document.title = props.route.meta.title;
}
const isLogin = !!localStorage.getItem('token');
if (props?.route?.meta?.auth) {
if (!isLogin) {
return <Navigate to={'/login'} replace />;
}
}
const location = useLocation();
const routerKey = location.pathname;
if (isLogin && ['/login'].includes(routerKey)) {
return <Navigate to={'/'} replace />;
}
return <div>{props.children}</div>;
};
// 渲染路由
const renderRoutes = routes => {
return routes.map(item => {
const route = { meta: item.meta, path: item.path };
route.element = <RouterBeforeEach route={item}>{item.element}</RouterBeforeEach>;
if (item.children) {
route.children = renderRoutes(item.children);
}
return route;
});
};
export default function Router() {
return useRoutes(renderRoutes(routes));
}
ルートを登録する
// App.jsx
import NavBar from './components/NavBar';
import Router from './routes/routerBefore';
const App = () => {
return (
<div className='app'>
<NavBar></NavBar>
{/* 注册路由 */}
{/* {Router()} */}
<Router></Router>
</div>
);
};
export default App;
他の
4k ワードは、React Router 6.4 の大きな変更点である Data API の導入を紹介します。あなたはもう純粋ではありません!- ナゲッツ (juejin.cn)
react-router v6 ルーティング ガードのベスト プラクティス! - ナゲッツ (juejin.cn)