如何在React Router中生成动态路由?

时间:2019-07-11 00:01:33

标签: javascript reactjs react-router

我正在尝试创建房屋列表,单击每个房屋都将指向带有该房屋数据的单独页面。当前,所有数据都是我在构造函数中创建的名为leaseData的静态数据。我希望Route path指向/dashboard/lease-id。我正在尝试将地址和MonthlyRent都传递到Lease组件中,以便可以在新组件中呈现该数据。我该怎么做呢?

import React, { Component } from 'react'
import { Link, Route } from 'react-router-dom'
import { Lease } from './Lease'

class Dashboard extends Component {
  constructor(props) {
    super(props)
    this.match = this.props.match

    this.leaseData = [
      {
        id: 1,
        address: '18291 Rainbow Dr, Cool Springs CA 93102',
        monthlyRent: 4300
      },
      {
        id: 2,
        address: '2200 Stiller Dr, Las Vegas NV 96274',
        monthlyRent: 1500
      },
      {
        id: 3,
        address: '21626 Sleepy Hollow Ct, Walnut CA 91763',
        monthlyRent: 2400
      }
    ]
  }

  render() {

    let linkList = this.leaseData.map(lease => {
      return (
        <li>
          <Link to={`${this.match.url}/${lease.id}`}>
          <img src="https://cdn.edinarealty.com/media/2256/homepage-tiles_new-construction.jpg" alt="HTML5 Icon"></img>
          </Link>
        </li>
      )
    })

    return (
      <div>
        MAIN DASHBOARD
        <ul>
         <li> {linkList} </li>
        </ul>
        <Route path={`${this.match.url}/:lease-id`} render={<Lease data={}/>}/>
      </div>
    )
  }
}

3 个答案:

答案 0 :(得分:1)

让我们尝试将App和Dashboard逻辑分开,以便我们可以更清晰地呈现事物。

这里是一个供参考的沙盒:https://codesandbox.io/s/suspicious-merkle-4bxv3

App.js

import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, Route } from "react-router-dom";
import Dashboard from "./Dashboard";
import Lease from "./Lease";

import "./styles.css";

class App extends React.Component {
  state = {
    leaseData: [
      {
        id: 1,
        address: "18291 Rainbow Dr, Cool Springs CA 93102",
        monthlyRent: 4300
      },
      {
        id: 2,
        address: "2200 Stiller Dr, Las Vegas NV 96274",
        monthlyRent: 1500
      },
      {
        id: 3,
        address: "21626 Sleepy Hollow Ct, Walnut CA 91763",
        monthlyRent: 2400
      }
    ],
    selected: null
  };

  changeSelected = id => {
    this.setState({
      selected: this.state.leaseData.find(lease => lease.id == id)
    });
  };

  render() {
    return (
      <BrowserRouter>
        <Route
          path="/"
          exact
          render={props => <Dashboard data={this.state.leaseData} />}
        />
        <Route
          path="/lease/:id"
          render={props => (
            <Lease
              {...props}
              selected={this.state.selected}
              changeSelected={this.changeSelected}
            />
          )}
        />
      </BrowserRouter>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Dashboard.js

import React, { Component } from "react";
import { Link } from "react-router-dom";

class Dashboard extends Component {
  render() {
    let linkList = this.props.data.map((lease, index) => {
      return (
        <li key={index}>
          <Link to={`/lease/${lease.id}`}>
            <img
              src="https://cdn.edinarealty.com/media/2256/homepage-tiles_new-construction.jpg"
              alt="HTML5 Icon"
            />
          </Link>
        </li>
      );
    });

    return (
      <div>
        MAIN DASHBOARD
        <ul>{linkList}</ul>
      </div>
    );
  }
}

导出默认仪表板;

Lease.js

import React, { useEffect } from "react";
import { Link } from "react-router-dom";

const Lease = props => {
  useEffect(() => {
    const id = props.match.params.id;
    props.changeSelected(id);
  }, []);

  const { selected } = props;

  if (!selected) {
    return <div>Loading...</div>;
  } else {
    return (
      <div>
        <Link to="/">Back to home</Link>
        <h4>Id: {selected.id}</h4>
        <h4>Address: {selected.address}</h4>
        <h4>Rent: {selected.monthlyRent}</h4>
      </div>
    );
  }
};

export default Lease;

主要说明:

  1. App.js包含我们的路由器,租约数据和选定的租约。
  2. 通过使用render道具,我们可以从 应用状态,到Route的组件。对于资讯主页路线,我们传入整个lease-data。对于“租赁”路线,我们传入changeSelected()来帮助检索选定的租赁项目,而selected就是找到的租赁项目。另外,我们散布了{... props}以访问matchhistory之类的道具。
  3. 在仪表板中,我们使用您设置的相同列表生成逻辑来显示项目。
  4. 当您单击图像并重定向到Lease组件时,我们将启动changeSelected函数。这发生在useEffect()中,我们使用props.match.params.id来获取通过Link导航到的租约的ID(也在URL中)。
  5. 将该值传递给changeSelected(),它将使用列表中指定的租赁对象更新App状态中的selected值。
  6. App.js被重新渲染(由于状态更改),并将selected项目状态值向下传递到Lease,我们将使用它显示该租约的信息对象。

总的来说,在集成redux之前这是一种干净的方法。

答案 1 :(得分:0)

您可以使用路由器交换机来生成租用路由,如下所示:

import React, { Component } from 'react'
import { Switch, Link, Route } from 'react-router-dom'
import { Lease } from './Lease'

class Dashboard extends Component {
  constructor(props) {
    super(props)
    this.match = this.props.match

    this.leaseData = [
      {
        id: 1,
        address: '18291 Rainbow Dr, Cool Springs CA 93102',
        monthlyRent: 4300
      },
      {
        id: 2,
        address: '2200 Stiller Dr, Las Vegas NV 96274',
        monthlyRent: 1500
      },
      {
        id: 3,
        address: '21626 Sleepy Hollow Ct, Walnut CA 91763',
        monthlyRent: 2400
      }
    ]
  }

  render() {

    let linkList = this.leaseData.map(lease => {
      return (
        <li>
          <Link to={`${this.match.url}/${lease.id}`}>
          <img src="https://cdn.edinarealty.com/media/2256/homepage-tiles_new-construction.jpg" alt="HTML5 Icon"></img>
          </Link>
        </li>
      )
    })

    let leaseRoutes = this.leaseData.map(lease => <Route exact path={`${this.match.url}/${lease.id}`} render={<Lease data={lease}/>}/>)

    return (
      <div>
        MAIN DASHBOARD
        <ul>
         <li> {linkList} </li>
        </ul>
        <Switch>
            {leaseRoutes}
        </Switch>
        <Route path={`${this.match.url}/:lease-id`} render={<Lease data={}/>}/>
      </div>
    )
  }
}

答案 2 :(得分:0)

sandbox

Dashboard中提取数据,这将使我们能够在挂载Lease组件时按ID查找数据

您可以在实现后端时将其替换为api调用

const data = [
  {
    id: 1,
    address: "18291 Rainbow Dr, Cool Springs CA 93102",
    monthlyRent: 4300
  },
  {
    id: 2,
    address: "2200 Stiller Dr, Las Vegas NV 96274",
    monthlyRent: 1500
  },
  {
    id: 3,
    address: "21626 Sleepy Hollow Ct, Walnut CA 91763",
    monthlyRent: 2400
  }
];

match.params.leaseId中提取leaseId并在使用leaseId作为依赖项的useEffect进行组件安装时进行查找

准备好api后,您可以将data.find替换为带有leaseId的API调用

“在装载时查找它”的原因是,它使我们能够直接访问URL,而无需通过仪表板来加载数据

const Lease = ({
  match: {
    params: { leaseId }
  }
}) => {
  const [leaseData, setLeaseData] = useState(null);

  useEffect(() => {
    setLeaseData(data.find(d => d.id.toString() === leaseId));
  }, [leaseId]);

  if (!leaseData) return null;

  return (
    <div>
      <h1>{leaseData.id}</h1>
      <p>{leaseData.address}</p>
      <p>{leaseData.monthlyRent}</p>
    </div>
  );
};

当url为/dashboard时,使用渲染道具渲染主Dashboard,并创建一个Route到leaseId的路径

const Dashboard = ({ match: { url } }) => {
  const linkList = data.map(lease => {
    return (
      <li key={lease.id}>
        <Link to={`${url}/${lease.id}`}>
          <img
            src="https://cdn.edinarealty.com/media/2256/homepage-tiles_new-construction.jpg"
            alt="HTML5 Icon"
          />
        </Link>
      </li>
    );
  });

  return (
    <Switch>
      <Route
        exact
        path={url}
        render={() => (
          <div>
            MAIN DASHBOARD
            <ul>{linkList}</ul>
          </div>
        )}
      />
      <Route path={`${url}/:leaseId`} component={Lease} />
    </Switch>
  );
};

const Home = () => (
  <div>
    <Link to="/dashboard">Dashboard</Link>
  </div>
);

const App = () => (
  <Router>
    <Switch>
      <Route exact path="/" component={Home} />
      <Route path="/dashboard" component={Dashboard} />
    </Switch>
  </Router>
);