如何将 id 传递给 React Js 路径链接?

ali*_*lia 3 javascript reactjs react-router

我正在尝试为我的 React Js 项目创建类似“/products?id=uniqueId”的组件路径。唯一 ID 取自数据库,取决于选择的产品。我的代码是

代码沙盒

应用程序.js

import "./styles.css";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import Products from "./Products"
import Home from "./Home"

export default function App() {
  return (
    <div className="App">
        <Router>
                <Switch>
                <Route exact path="/">
                        {" "}
                        <Home/>
                    </Route>
                    <Route exact path="/products">
                        {" "}
                        <Products />
                    </Route>
                </Switch>
            </Router>
    </div>
  );
}

Run Code Online (Sandbox Code Playgroud)

主页.js

import "./styles.css";
import React, { useState } from "react";
import { useHistory } from "react-router-dom";

const products = [
  {
    id: "1",
    name: "Product 1"
  },
  {
    id: "2",
    name: "Product 2"
  },
  {
    id: "3",
    name: "Product 3"
  }
];

export default function Home() {
  const [id, setId] = useState();
  const history = useHistory();

  const handleProceed = (e) => {
    // console.log(id, "home");
    history.push("/products", { id });
  };

  return (
    <div
      style={{ display: "flex", flexDirection: "column", alignItems: "center" }}
    >
      <div>
        {products.map((product) => {
          return (
            <button
              onClick={(e) => {
                setId(product.id);
              }}
            >
              {product.name}{" "}
            </button>
          );
        })}
      </div>
      <button onClick={handleProceed} style={{ width: "250px" }}>
        {" "}
        Proceed
      </button>
    </div>
  );
}


Run Code Online (Sandbox Code Playgroud)

产品.js

import "./styles.css";
import { useLocation } from "react-router-dom";

export default function Home() {
  const location = useLocation();
  const { id } = location.state || { id: "none" };

  console.log(id);
  return (
    <div>
      <p> Lorem Ipsum</p>
    </div>
  );
}

Run Code Online (Sandbox Code Playgroud)

想法是,当用户按下 < Home /> 组件中带有产品名称的任何按钮时,页面应重定向到 < Product /> 组件,路径应为“/products?id=uniqueId”,其中 uniqueId = 到product.id。我能够使用 useHistory() 和 useLocation() 将 Product.id 从 < Home /> 传递到 < Product /> ,但我不知道如何使路径显示选定的 id 。例如,如果用户单击“产品 1”按钮,< Product /> 的路径应为“/products?id=1”,如果选择“产品 2”,路径应将其反映为“/products?id=2”,依此类推。

非常感谢任何帮助和建议。

Dre*_*ese 14

我建议将产品作为id路径的一部分,而不是将其放在查询字符串中。作为路径的一部分,它几乎不需要代码中的任何内容即可访问,而如果您使用查询字符串,则需要将整个查询字符串解析为键值对的映射。

  1. 定义您的路径以包含id

    <Route path="/products/:id">
      <Products />
    </Route>
    
    Run Code Online (Sandbox Code Playgroud)
  2. 在产品页面上使用useParams反应钩子来访问id路线匹配参数。

    const { id } = useParams();
    
    Run Code Online (Sandbox Code Playgroud)
  3. id生成带有参数的路径

    const handleProceed = (e) => {
      history.push(generatePath("/products/:id", { id }));
    };
    
    Run Code Online (Sandbox Code Playgroud)

    或者如果你喜欢生吃

    const handleProceed = (e) => {
      history.push(`/products/${id}`));
    };
    
    Run Code Online (Sandbox Code Playgroud)

Route我进一步建议通过重新排序组件以首先指定更具体的路径来优化路由。这可以让您避免将exactprop 传递到每条路线。

<Router>
  <Switch>
    <Route path="/products/:id">
      <Products />
    </Route>
    <Route path="/">
      <Home />
    </Route>
  </Switch>
</Router>
Run Code Online (Sandbox Code Playgroud)

演示

编辑 how-to-pass-id-to-react-js-path-link

完整演示代码:

import { useState } from "react";
import {
  BrowserRouter as Router,
  generatePath,
  Switch,
  Route,
  useHistory,
  useParams
} from "react-router-dom";

const products = [
  {
    id: "1",
    name: "Product 1"
  },
  {
    id: "2",
    name: "Product 2"
  },
  {
    id: "3",
    name: "Product 3"
  }
];

const Products = () => {
  const { id } = useParams();

  console.log(id);
  return (
    <div>
      <p>Lorem Ipsum</p>
      <p>Id: {id}</p>
    </div>
  );
};

const Home = () => {
  const [id, setId] = useState();
  const history = useHistory();

  const handleProceed = (e) => {
    id && history.push(generatePath("/products/:id", { id }));
  };

  return (
    <div
      style={{ display: "flex", flexDirection: "column", alignItems: "center" }}
    >
      <div>
        {products.map((product, i) => (
          <button
            key={i}
            onClick={(e) => {
              setId(product.id);
            }}
          >
            {product.name}
          </button>
        ))}
      </div>
      <button onClick={handleProceed} style={{ width: "250px" }}>
        Proceed
      </button>
    </div>
  );
};

export default function App() {
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <Router>
        <Switch>
          <Route path="/products/:id">
            <Products />
          </Route>
          <Route path="/">
            <Home />
          </Route>
        </Switch>
      </Router>
    </div>
  );
}
Run Code Online (Sandbox Code Playgroud)

react-router-dom@6兼容版本:

import { useState } from "react";
import {
  BrowserRouter as Router,
  generatePath,
  Routes,
  Route,
  useNavigate,
  useParams,
} from "react-router-dom";

const products = [
  {
    id: "1",
    name: "Product 1"
  },
  {
    id: "2",
    name: "Product 2"
  },
  {
    id: "3",
    name: "Product 3"
  }
];

const Products = () => {
  const { id } = useParams();

  console.log(id);
  return (
    <div>
      <p>Lorem Ipsum</p>
      <p>Id: {id}</p>
    </div>
  );
};

const Home = () => {
  const [id, setId] = useState();
  const navigate = useNavigate();

  const handleProceed = (e) => {
    id && navigate(generatePath("/products/:id", { id }));
  };

  return (
    <div
      style={{ display: "flex", flexDirection: "column", alignItems: "center" }}
    >
      <div>
        {products.map((product, i) => (
          <button
            key={i}
            onClick={(e) => {
              setId(product.id);
            }}
          >
            {product.name}
          </button>
        ))}
      </div>
      <button onClick={handleProceed} style={{ width: "250px" }}>
        Proceed
      </button>
    </div>
  );
};

export default function App() {
  return (
    <div className="App">
      <Router>
        <Routes>
          <Route path="/products/:id" element={<Products />} />
          <Route path="/" element={<Home />} />
        </Switch>
      </Router>
    </div>
  );
}
Run Code Online (Sandbox Code Playgroud)