How do I route to individual pages using index number instead of id of the object?

Issue

I am quite new to useParams and ExpressJS and am trying to use it to display a detailed user profile after clicking on a list of profiles tagged with their profile number. The user profiles are an object stored in an array. I am trying to get the link in the browser to display it as "https://localhost/3000/profile/1" where 1 is the index number instead of the profile number like "https://localhost/3000/profile/A123".

Data is being stored in profile.json:
[{"PROFILE_NUMBER": "A123", "NAME": "X", "AGE" : "21", "HOBBY" : "RUN"} , …..]

In the utils.js

const getProfiles = async () => {
  // Retrieve sightings.json file contents as string
  const profiles = await readFile("./profiles.json", "utf8");
  // Return sightings as an object
  return JSON.parse(profiles);
};


module.exports = {
  getProfiles
}

Here is my index.js in my backend folder

const express = require("express");
const { getProfile } = require("./utils.js");
var cors = require("cors");

require("dotenv").config();

const PORT = process.env.PORT;
const app = express();
app.use(cors());

app.get("/profiles", async (req, res) => {
  const profiles = await getProfile();
  res.json(profiles);
});

app.get("/profiles/:profileIndex", async (req, res) => {
  const profiles = await getProfile();
  res.json(profiles[req.params.profileIndex]);
});

app.listen(PORT, () => {
  console.log(`Express app listening on port ${PORT}!`);
});

On the other hand, for my frontend.
This is my App.js where the data is being called from the backend:

import React from "react";
import "./App.css";
import Card from "./Card";
import Single from "./Single";
import { Routes, Route } from "react-router-dom";


class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      profiles: [],
    };
  }

  componentDidMount() {
    fetch("http://localhost:3000/profiles")
      .then((response) => response.json())
      .then((data) => {
        this.setState({ profiles: data });
      });
  }

  render() {
    return (
      <div className="App">
        <Routes>
          <Route
            exact
            path="/profile"
            element={<Card profiles={this.state.profiles} />}
          ></Route>
          <Route
            path="/profiles/:profileIndex"
            element={<Single profiles={this.state.profiles} />}
          ></Route>
        </Routes>
      </div>
    );
  }
}

export default App;

This is my Card.js which is the list of user profiles displayed.

import React from "react";
import "./App.css";
import { Link } from "react-router-dom";

const Card = ({ profiles }) => {
  return (
    <div className="App">
      {profiles.map((profile) => (
        <div className="container">
          <Link
            style={{ display: "block", margin: "1rem 0" }}
            to={`/profiles/${profile.PROFILE_NUMBER}`}
            key={profile.PROFILE_NUMBER}
          >
            <div>
              {profile.PROFILE_NUMBER}
              <br />
              {profile.NAME}
              <br />
            </div>
          </Link>
        </div>
      ))}
    </div>
  );
};

export default Card;

Lastly, this is the Single.js where it display individual profile

import React from "react";
import { useParams } from "react-router-dom";
import "./App.css";

const Single = ({ profiles }) => {
  let params = useParams();
 

  var newArray = profiles.filter(function (el) {
    return el.PROFILE_NUMBER === params.profileIndex;
  });

  return (
    <div className="App">
      {console.log(newArray)}
      {`Report Number: ${newArray[0].PROFILE_NUMBER}`}
      <br />
      {`County: ${newArray[0].NAME}`}
      <br />
      {`Year: ${newArray[0].AGE}`}
      <br />
      {`Description: ${newArray[0].HOBBY}`}
    </div>
  );
};

export default Single;

How do I get the link to display index number and show the correct user profile instead of using the profile number? Any guidance on how to implement a search function too? Thank you!

Solution

If you want the profileIndex route path param to be the profiles array index instead of the specific profile number of an element in the array then pass the mapped index in the link and use the profileIndex param as the array index when pulling a profile object from the array.

Example:

const Card = ({ profiles }) => {
  return (
    <div className="App">
      {profiles.map((profile, index) => (
        <div className="container">
          <Link
            style={{ display: "block", margin: "1rem 0" }}
            to={`/profiles/${index}`} // <-- pass array index here
            key={profile.PROFILE_NUMBER}
          >
            <div>
              {profile.PROFILE_NUMBER}
              <br />
              {profile.NAME}
              <br />
            </div>
          </Link>
        </div>
      ))}
    </div>
  );
};

const Single = ({ profiles }) => {
  const { profileIndex } = useParams();

  const profile = profiles[profileIndex];

  if (!profile) {
    return "No Profile";
  }

  return (
    <div className="App">
      {`Report Number: ${profile.PROFILE_NUMBER}`}
      <br />
      {`County: ${profile.NAME}`}
      <br />
      {`Year: ${profile.AGE}`}
      <br />
      {`Description: ${profile.HOBBY}`}
    </div>
  );
};

Answered By – Drew Reese

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published