Home > Software design >  React Dom Routes not working as intended, changes the path but nothing on the page
React Dom Routes not working as intended, changes the path but nothing on the page

Time:05-18

I am making a webplatform working with the OpenLibrary API, I am pulling data from the subjects then when you click on one of the books in the subjects, I want to be taken to a page called 'Book' where I display the data. Now I have set up my Routes (i think they're correct), but when I click one of the items in the list, it doesn't do anything, it changes the URL to the route I set up, but it doesn't take me to the Book component where I display the data. Now, I haven't posted my Book.js file because it just has test code in it to see if I can get to the component. Any help will be appreciated!

Here are some snippets of my code:

App.js:

import React, { useState, useEffect } from "react";
import axios from "axios";

import Works from "./components/Works";
import Navbar from "./components/Navbar";
import Footer from "./components/Footer";

import "./styles.css";

function App() {
  const [subjects, setSubjects] = useState([]);
  const [worksDetails, setWorkDetails] = useState([]);
  const [isLoading, setIsLoading] = useState(false);
  const url = "https://openlibrary.org/subjects/animals.json?limit=10";
  useEffect(() => {
    axios
      .get(url)
      .then((response) => {
        setSubjects(response.data);
        setWorkDetails(response.data.works);
        setIsLoading(true);
      })
      .catch((error) => {
        console.log(error);
      });
  }, []);

  if (!isLoading) {
    return <p>Loading...</p>;
  } else {
    return (
      <>
        <Navbar />
        <div className="contentHeader">
          <h1 className="subjectHeader" style={{ padding: "10px" }}>
            Subject: {subjects.name.toUpperCase()}
          </h1>
          <h1 className="workHeader" style={{ padding: "10px" }}>
            Work Count: {subjects.work_count.toLocaleString()}
          </h1>
        </div>
        <div>
          <Works works={worksDetails} />
        </div>
        <Footer />
      </>
    );
  }
}
export default App;

Works.js

import React from "react";
import { Link } from "react-router-dom";
import Book from "../routes/Book";

const Works = (props) => {
  return (
    <div className="container">
      <div>
        <div className="heading">
          {props.works.map((work) => {
            return (
              <Link to={`/book/${work.key}`} element={<Book />} key={work.key}>
                <ul>{work.title}</ul>
              </Link>
            );
          })}
        </div>
      </div>
    </div>
  );
};

export default Works;

Index.js

import { createRoot } from "react-dom/client";
import "./index.css";
import { BrowserRouter, Routes, Route } from "react-router-dom";

import App from "./App";
import Book from "./routes/Book";

const rootElement = document.getElementById("root");
const root = createRoot(rootElement);

root.render(
  <BrowserRouter>
    <Routes>
      <Route path="*" element={<App />} />
      <Route path="/book" element={<Book />}>
        <Route path=":bookId" element={<Book />} />
      </Route>
    </Routes>
  </BrowserRouter>
);

CodePudding user response:

Issue

When you use

<Route path="/book" element={<Book />}>
  <Route path=":bookId" element={<Book />} />
</Route>

The Route component is expecting Book to render an Outlet component for the nested Route component. This doesn't appear to be the UX you are going for though. The outer route is matched and rendered, but then because there's no outlet the inner route rendering the actual Book component you want with the param isn't rendered at all.

It turns out that in the fetched data that work.key isn't just an id, but a nested route value it seems, i.e. something like "key": "/works/OL138052W", so the UI is computing a malformed route ("/book//works/OL138052W") and linking to a route that doesn't exist.

Solution

to={`/book${work.key}`} is the path you are linking to, note the removal of the "/" between "book" and the injected work.key value:

<Link key={work.key} to={`/book${work.key}`}>
  <ul>{work.title}</ul>
</Link>

Then the should render one of the following:

<Route path="/book/works/:bookId" element={<Book />} />

or

<Route path="/book/works">
  <Route path=":bookId" element={<Book />} /> // "/book/works/:bookId"
</Route>

Edit react-dom-routes-not-working-as-intended-changes-the-path-but-nothing-on-the-pa

If you don't want to mess with this work.key value then you may want to select one of the other properties, so long as they provide sufficient uniqueness for identification purposes.

CodePudding user response:

I believe your Route should look like this:

<Route path="/book/:bookId" element={<Book />}>
  • Related