How do I use a dynamic URL that won't redirect to error page when the URL doesn't match any of the routes I've declared? – react-router-dom

huangapple go评论109阅读模式
英文:

How do I use a dynamic URL that won't redirect to error page when the URL doesn't match any of the routes I've declared? - react-router-dom

问题

我创建了一个使用react-router-dom的项目,我希望URL包含一个id。该id将用于从数据库中获取与该id对应的项目信息并在页面上呈现它。我已经成功地根据URL中的id实现了数据加载。

我的问题是,react-router-dom似乎将带有id的URL解释为未知路由,并将其重定向到我的错误页面。

这是我的路由设置方式:

  1. const router = createBrowserRouter([
  2. {
  3. path: "/",
  4. element: <Root />,
  5. errorElement: <Error />,
  6. children: [
  7. { path: "/", element: <Home /> },
  8. { path: "progress", element: <Progress /> },
  9. { path: "logworkout", element: <LogWorkout /> },
  10. {
  11. path: "programs",
  12. element: <Programs />,
  13. children: [
  14. { index: true, element: <Navigate to="myprograms" replace /> },
  15. { path: "discover", element: <DiscoverPrograms /> },
  16. {
  17. path: "myprograms",
  18. element: <MyPrograms />,
  19. children: [
  20. {
  21. path: ":programID",
  22. element: <ProgramView />,
  23. loader: programViewLoader,
  24. },
  25. ],
  26. },
  27. ],
  28. },
  29. { path: "product", element: <Product /> },
  30. { path: "contact", element: <Contact /> },
  31. ],
  32. },
  33. ]);

我基本上希望/programs/myprograms/:programID能够呈现,而不是错误页面。我认为我很好地遵循了react-router-dom文档中的教程,但我无法弄清楚我漏掉了什么。

编辑:仅/programs中的<Programs/>渲染了一个<Outlet>

  1. import SideBar from "../../components/Programs/SideBar";
  2. import { Outlet } from "react-router-dom";
  3. const Programs = () => {
  4. return (
  5. <div className="grid overflow-hidden" style={{ gridTemplateColumns: "auto 1fr" }}>
  6. <SideBar />
  7. <div className="overflow-auto">
  8. <Outlet />
  9. </div>
  10. </div>
  11. );
  12. };
  13. export default Programs;

编辑:问题不在于动态路由,而在于我用于<ProgramView/>的加载器函数。显然,我没有在加载器中返回值。

  1. import Cookies from "js-cookie";
  2. import { refreshToken } from "../../../../util/auth";
  3. export const programViewLoader = ({ params }) => {
  4. refreshToken()
  5. .then((refresh) => {
  6. return fetch("http://localhost:5000/program/load-program", {
  7. method: "POST",
  8. headers: {
  9. "Content-type": "application/json",
  10. Authorization: `Bearer ${Cookies.get("accessToken")}`,
  11. },
  12. body: JSON.stringify({
  13. programID: params.programID,
  14. }),
  15. });
  16. })
  17. .then((response) => {
  18. if (!response.ok) {
  19. return response.json().then((data) => {
  20. throw { error: data.error, status: response.status };
  21. });
  22. }
  23. return response.json();
  24. })
  25. .then((data) => {
  26. console.log(data.program);
  27. return data.program;
  28. })
  29. .catch((error) => {
  30. return { error: "加载程序时发生错误。" };
  31. });
  32. };

然而,console.log()总是打印出某些内容,所以我不确定为什么它没有返回任何内容。

英文:

I am creating a project with react-router-dom where I want the URL to hold an id. The id will be used to fetch information about the item with that id from a database and render it on the page. I've already successfully implemented data loading based on the id in the url.

My issue is that react-router-dom seems to interpret the url with the id as an unknown route and redirects it to my error page.

This is how my routes are set up:

  1. const router = createBrowserRouter([
  2. {
  3. path: &quot;/&quot;,
  4. element: &lt;Root /&gt;,
  5. errorElement: &lt;Error /&gt;,
  6. children: [
  7. { path: &quot;/&quot;, element: &lt;Home /&gt; },
  8. { path: &quot;progress&quot;, element: &lt;Progress /&gt; },
  9. { path: &quot;logworkout&quot;, element: &lt;LogWorkout /&gt; },
  10. {
  11. path: &quot;programs&quot;,
  12. element: &lt;Programs /&gt;,
  13. children: [
  14. { index: true, element: &lt;Navigate to=&quot;myprograms&quot; replace /&gt; },
  15. { path: &quot;discover&quot;, element: &lt;DiscoverPrograms /&gt; },
  16. {
  17. path: &quot;myprograms&quot;,
  18. element: &lt;MyPrograms /&gt;,
  19. children: [
  20. {
  21. path: &quot;:programID&quot;,
  22. element: &lt;ProgramView /&gt;,
  23. loader: programViewLoader,
  24. },
  25. ],
  26. },
  27. ],
  28. },
  29. { path: &quot;product&quot;, element: &lt;Product /&gt; },
  30. { path: &quot;contact&quot;, element: &lt;Contact /&gt; },
  31. ],
  32. },
  33. ]);

I basically want /programs/myprograms/:programID to render instead of the error page. I think I followed the tutorial on react-router-dom's documentation pretty well and I can't figure out what I'm missing.

Edit: Only &lt;Programs/&gt; in /programs renders an Outlet

  1. import { Outlet } from &quot;react-router-dom&quot;;
  2. const Programs = () =&gt; {
  3. return (
  4. &lt;div className=&quot;grid overflow-hidden&quot; style={{gridTemplateColumns: &quot;auto 1fr&quot;}}&gt;
  5. &lt;SideBar /&gt;
  6. &lt;div className=&quot;overflow-auto&quot;&gt;
  7. &lt;Outlet /&gt;
  8. &lt;/div&gt;
  9. &lt;/div&gt;
  10. );
  11. };
  12. export default Programs;

Edit: The issue isn't about the dynamic route but about the loader function I'm using for &lt;ProgramView/&gt;. Apparently, I'm not returning a value in the loader.

  1. import Cookies from &quot;js-cookie&quot;;
  2. import { refreshToken } from &quot;../../../../util/auth&quot;;
  3. export const programViewLoader = ({ params }) =&gt; {
  4. refreshToken()
  5. .then((refresh) =&gt; {
  6. return fetch(&quot;http://localhost:5000/program/load-program&quot;, {
  7. method: &quot;POST&quot;,
  8. headers: {
  9. &quot;Content-type&quot;: &quot;application/json&quot;,
  10. Authorization: `Bearer ${Cookies.get(&quot;accessToken&quot;)}`,
  11. },
  12. body: JSON.stringify({
  13. programID: params.programID,
  14. }),
  15. });
  16. })
  17. .then((response) =&gt; {
  18. if (!response.ok) {
  19. return response.json().then((data) =&gt; {
  20. throw { error: data.error, status: response.status };
  21. });
  22. }
  23. return response.json();
  24. })
  25. .then((data) =&gt; {
  26. console.log(data.program);
  27. return data.program;
  28. })
  29. .catch((error) =&gt; {
  30. return { error: &quot;An error occurred while loading the program.&quot; };
  31. });
  32. };

However the console.log() always prints something so I'm not sure how it isn't returning anything

答案1

得分: 1

只有&lt;Programs /&gt;&quot;/programs&quot;中渲染Outlet

这只允许直接嵌套的路由渲染到父路由组件的Outlet中,例如:

  • &quot;/programs&quot;索引路由上的Navigate
  • &quot;/programs/discover&quot;上的DiscoverPrograms
  • &quot;/programs/myprograms&quot;上的MyPrograms

这些组件中的任何一个都需要再次渲染自己的Outlet,以渲染可能的嵌套路由。

  1. const MyPrograms = () =&gt; {
  2. ...
  3. return (
  4. ...
  5. &lt;Outlet /&gt;
  6. ...
  7. );
  8. };

现在ProgramView应该可以通过MyProgramsOutlet通过ProgramsOutlet&quot;/programs/myprograms/:programID&quot;上渲染。

programViewLoader没有返回值。refreshToken函数返回一个Promise链,但您需要实际从加载器函数返回Promise链的结果。

  1. export const programViewLoader = ({ params }) =&gt; {
  2. return refreshToken() // &lt;-- 返回Promise链!
  3. .then((refresh) =&gt; {
  4. return fetch(&quot;http://localhost:5000/program/load-program&quot;, {
  5. method: &quot;POST&quot;,
  6. headers: {
  7. &quot;Content-type&quot;: &quot;application/json&quot;,
  8. Authorization: `Bearer ${Cookies.get(&quot;accessToken&quot;)}`,
  9. },
  10. body: JSON.stringify({
  11. programID: params.programID,
  12. }),
  13. });
  14. })
  15. .then((response) =&gt; {
  16. if (!response.ok) {
  17. return response.json().then((data) =&gt; {
  18. throw { error: data.error, status: response.status };
  19. });
  20. }
  21. return response.json();
  22. })
  23. .then((data) =&gt; {
  24. console.log(data.program);
  25. return data.program;
  26. })
  27. .catch((error) =&gt; {
  28. return { error: &quot;加载程序时发生错误&quot; };
  29. });
  30. };
英文:

> Only &lt;Programs /&gt; in &quot;/programs&quot; renders an Outlet

This allows only the immediately nested routes to be rendered into the parent route component's Outlet, e.g:

  • Navigate on the &quot;/programs&quot; index route
  • DiscoverPrograms on &quot;/programs/discover&quot;
  • MyPrograms on &quot;/programs/myprograms&quot;

Any of these components would need to, yet again, render another Outlet of their own for any nested routes they may be rendering.

  1. const MyPrograms = () =&gt; {
  2. ...
  3. return (
  4. ...
  5. &lt;Outlet /&gt;
  6. ...
  7. );
  8. };

Now ProgramView should be renderable via MyPrograms' Outlet via Programs' Outlet on &quot;/programs/myprograms/:programID&quot;.

The programViewLoader isn't returning a value. The refreshToken function returns a Promise chain, but then you need to actually return the result of the Promise chain from the loader function.

  1. export const programViewLoader = ({ params }) =&gt; {
  2. return refreshToken() // &lt;-- return Promise chain!
  3. .then((refresh) =&gt; {
  4. return fetch(&quot;http://localhost:5000/program/load-program&quot;, {
  5. method: &quot;POST&quot;,
  6. headers: {
  7. &quot;Content-type&quot;: &quot;application/json&quot;,
  8. Authorization: `Bearer ${Cookies.get(&quot;accessToken&quot;)}`,
  9. },
  10. body: JSON.stringify({
  11. programID: params.programID,
  12. }),
  13. });
  14. })
  15. .then((response) =&gt; {
  16. if (!response.ok) {
  17. return response.json().then((data) =&gt; {
  18. throw { error: data.error, status: response.status };
  19. });
  20. }
  21. return response.json();
  22. })
  23. .then((data) =&gt; {
  24. console.log(data.program);
  25. return data.program;
  26. })
  27. .catch((error) =&gt; {
  28. return { error: &quot;An error occurred while loading the program.&quot; };
  29. });
  30. };

huangapple
  • 本文由 发表于 2023年8月10日 14:58:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/76873281.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定