根据异步获取的数据来响应路由器条件重定向URL

时间:2019-11-13 05:35:23

标签: javascript reactjs react-router

我下面有一个代码框,显示我的情况:

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/overviewdataset.versions

但是我下面的代码有一个错误:当数据集没有版本时,路由将更改为/dataset/overview/overview,而不是/dataset/overview。希望有人能帮助我解决这个问题。

2 个答案:

答案 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