我下面有一个代码框,显示我的情况:
https://codesandbox.io/embed/sad-nash-x4n69
我有一个名为dataset
的对象,可以有零个,一个或多个版本。如果dataset
有任何版本,该组件应显示最新版本,或显示默认的空白页面。由于这两个条件,该组件具有两条路径:/dataset
和/dataset/:version
:
如果数据集为空,则需要到/dataset/overview
的url路由,它应该是dataset
的基本信息。
如果数据集不为空,我需要将路由重定向到/dataset/${dataset.versions}
,它将显示最新版本的数据。
与此同时,DatasetView
组件具有三个选项卡:overview
versions
settings
。我希望页面会根据/dataset/overview
自动重定向到/dataset/:version/overview
或dataset.versions
。
但是我下面的代码有一个错误:当数据集没有版本时,路由将更改为/dataset/overview/overview
,而不是/dataset/overview
。希望有人能帮助我解决这个问题。
答案 0 :(得分:2)
虽然@dev_junwen的解决方案可能有效,但我想提供一种更简单的解决方案,并调查您原来的路由器不起作用的原因。
在您的代码中,路由器具有可以省略的参数version
。由于您没有将参数指定为可选参数,因此应用程序始终希望dataset
之后的代码为version
,并在不需要时附加另一个/overview
。
通过在Router
级别将其设置为可选,该应用程序应该可以运行。
<Route path={["/dataset/:version([0-9]+)?", "/dataset"]}>
为了使DatassetComponent
组件中的现有路由正常工作,我在version
参数中添加了一个正则表达式,使其仅与数字匹配。
在此处查看有效的代码沙箱:https://codesandbox.io/s/epic-beaver-c14kk
答案 1 :(得分:1)
起初,这个问题似乎很简单,但是花了我很长时间才弄清楚该怎么做!这是我现在能想到的唯一方法。如果有关于如何改进代码的建议,请随时提交更改请求:)
我不能保证这是最好的方法,但是它适用于您的情况。
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
import {
BrowserRouter as Router,
Route,
Switch,
NavLink,
useRouteMatch,
Redirect
} from "react-router-dom";
import "./styles.css";
const datasetWithVersions = {
id: "dataset-with-versions",
versions: 2,
versionList: [
{
version: 1,
size: 20001
},
{
version: 2,
size: 191232
}
],
name: "a-dataset-with-2-versions"
};
const datasetWithNoVerrsions = {
id: "dataset-with-no-versions",
versions: 0,
name: "an-empty-dataset"
};
function loadDataset() {
return new Promise(resolve => {
setTimeout(() => {
if (Math.random() >= 0.5) {
console.log("loading dataset with versions....");
resolve(datasetWithVersions);
} else {
console.log("loading dataset with no versions....");
resolve(datasetWithNoVerrsions);
}
}, 1000);
});
}
function App() {
return (
<div className="App">
<Router>
<Switch>
<Route path="/dataset" component={DatassetComponent} />
<Redirect to="/dataset" />
</Switch>
</Router>
</div>
);
}
function DatassetComponent() {
let [dataset, setDataset] = useState(null);
const match = useRouteMatch();
useEffect(() => {
loadDataset().then(data => setDataset(data));
}, []);
if (!dataset) return <div>loading...</div>;
const getURL = to => {
if (dataset.versions) {
return `${match.path}/${dataset.versions}/${to}`;
}
return `${match.path}/${to}`;
};
return (
<div>
<div className="navbar">
<NavLink to={getURL("overview")} activeClassName="active">
OverView
</NavLink>
{dataset.versions ? (
<NavLink to={getURL("versions")} activeClassName="active">
Versions
</NavLink>
) : null}
<NavLink to={getURL("settings")} activeClassName="active">
Settings
</NavLink>
</div>
<div className="content">
<Switch>
<Route path={getURL("versions")}>
<div>Versions</div>
</Route>
<Route path={getURL("settings")}>
<div>settings</div>
</Route>
<Route path={getURL("overview")}>
<div>Overview for dataset {dataset.name}</div>
</Route>
<Redirect to={getURL("overview")} />
</Switch>
</div>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
工作代码沙箱:https://codesandbox.io/s/react-router-optional-path-demo-p50b4?fontsize=14