Cant send a value to another page in react

64 Views Asked by At

Apologies if this is rudimentary, but I am not able to do a fairly simple task. I have a page where I have data rendered from an API into the cards like divisions. Ex:

<div class="card bg-light mb-3 offset-md-4" style={{ width: "30rem" }}>
  <div class="card-body">
    <h5 class="card-title">
      {post.userDetails != undefined ? post.userDetails.name : ""}
    </h5>
    <p class="card-text">{post.emailAddress}</p>
    <p class="card-text">
      {post.userDetails != undefined ? post.userDetails.phone : ""}
    </p>
  </div>
</div>;

For each data item, there is a card displayed on screen. I am trying to find a way to click one of these cards and show the data on Another page where I can Edit/ Delete the selected card's data, but I have not been able to succeed in doing so. Below is my full code:

import React, { Component, useState, useEffect } from "react";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import axios from "axios";
import { URL } from "../Data/Env";

export default class UserPanel extends Component {
  constructor(props) {
    super(props);
    this.state = {
      post: [],
    };
  }
  componentDidMount() {
    this.getUser();
  }
  async getUser() {
    let url = URL.concat("authors");
    axios
      .get(url)
      .then((response) => {
        console.log(response.data);
        if (response.data.statusCode == 200) {
          this.setState({ post: response.data.data });
        } else if (response.data.statusCode == 400) {
          console.log("User detail retrieving failed !!");
        } else {
          console.log("User detail unknown error !!");
        }
      })
      .catch((error) => {});
  }
  showUser(post) {
    return (
      <div>
        <Link
          to={{ pathname: "/UserDetail", state: [{ userId: post.userId }] }}
        >
          <div
            class="card bg-light mb-3 offset-md-4"
            style={{ width: "30rem" }}
          >
            <div class="card-body">
              <h5 class="card-title">
                {post.userDetails != undefined ? post.userDetails.name : ""}
              </h5>
              <p class="card-text">{post.emailAddress}</p>
              <p class="card-text">
                {post.userDetails != undefined ? post.userDetails.phone : ""}
              </p>
            </div>
          </div>
        </Link>
      </div>
    );
  }
  render() {
    const { post } = this.state;
    return (
      <div>
        <br />
        <br />
        <div>
          <div className="row col-md-12">
            <div className="offset-md-4">
              {" "}
              <h3>All Users</h3>{" "}
            </div>
            <div>
              <Link to={"/SignUp"}>
                <button
                  className="btn btn-success"
                  style={{ marginLeft: "146px", width: "234px" }}
                >
                  {" "}
                  Add User
                </button>
              </Link>
            </div>
          </div>
          <br />
        </div>
        <div> {post.map(this.showUser)}</div>
      </div>
    );
  }
}

Any help is really appreciated.

1

There are 1 best solutions below

2
Kavindu Vindika On BEST ANSWER

You shouldn't use <Link> outside <Router>. First you need to create the routes then you can use <Link> to navigate to the relevant page. It's better to have separate components relevant to each route. Refer this link for basic routing examples from react-router: https://reactrouter.com/web/guides/quick-start

For the OP's scenario, it is essential to have separate Users and UserDetail components, in which Users component shows all the users details and UserDetail component shows selected user details. UserPanel main component will be used to contain the routes of the application such as /UserDetail, /SignUp.

Following implementation can be used as a supprotive material for OP's scenario. In this case, data fetching from api has been mocked for the easiness of understanding.

UserPanel.js

import React, { Component } from "react";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import UserDetail from "./UserDetail";
import Users from "./Users";

export default class UserPanel extends Component {
  render() {
    return (
      <div>
        <Router>
          <br />
          <br />
          <div>
            <div className="row col-md-12">
              <div className="offset-md-4">
                {" "}
                <h3>All Users</h3>{" "}
              </div>
              <div>
                <Link to={"/SignUp"}>
                  <button
                    className="btn btn-success"
                    style={{ marginLeft: "146px", width: "234px" }}
                  >
                    Add User
                  </button>
                </Link>
              </div>
            </div>
            <br />
          </div>

          <Route exact path="/" component={Users} />
          <Route exact path="/UserDetail" component={UserDetail} />
        </Router>
      </div>
    );
  }
}

Users.js

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

const users = [
  {
    userId: 1,
    userDetails: { name: "john", phone: "111232" },
    emailAddress: "[email protected]",
  },
  {
    userId: 2,
    userDetails: { name: "kamal", phone: "2222" },
    emailAddress: "[email protected]",
  },
];

export default class Users extends Component {
  constructor(props) {
    super(props);
    this.state = {
      posts: [],
    };
  }
  componentDidMount() {
    this.getUser();
  }
  async getUser() {
    await Promise.resolve(users).then((data) => this.setState({ posts: data }));
    /*
    mocked data fetching needs to be replaced with actual api invokation
    */
  }
  showUser(post) {
    return (
      <div>
        <div class="card bg-light mb-3 offset-md-4" style={{ width: "30rem" }}>
          <div class="card-body">
            <Link to={{ pathname: "/UserDetail", state: { post } }}>
              <h5 class="card-title">
                {post.userDetails != undefined ? post.userDetails.name : ""}
              </h5>
            </Link>
            <p class="card-text">{post.emailAddress}</p>
            <p class="card-text">
              {post.userDetails != undefined ? post.userDetails.phone : ""}
            </p>
          </div>
        </div>
      </div>
    );
  }
  render() {
    const { posts } = this.state;
    return <div> {posts.map(this.showUser)}</div>;
  }
}

UserDetail.js

import React from "react";
import { useLocation } from "react-router-dom";

const UserDetail = () => {
  const location = useLocation();
  const { post } = location.state;

  return (
    <div class="card bg-light mb-3 offset-md-4" style={{ width: "30rem" }}>
      <div class="card-body">
        <h5 class="card-title">
          {post.userDetails != undefined ? post.userDetails.name : ""}
        </h5>
        <p class="card-text">{post.emailAddress}</p>
        <p class="card-text">
          {post.userDetails != undefined ? post.userDetails.phone : ""}
        </p>
      </div>
    </div>
  );
};

export default UserDetail;

Following are the application views for the relevant routes.

Route: /

enter image description here

Route: /UserDetail

enter image description here

In above implementation, each card's title (user name) has been linked to the /UserDetail route which shows user details. /SignUp route doesn't contain a component, but it can be routed to a particular child component as similar to Users and UserDetail components.

useLocation hook from react-router-dom is used to get the location object relevant to the current URL. From it, location state can be extracted.

Suggestions

  1. Since data fetched from api is an array of objects, keep it stored as posts instead of post. Be careful about variable naming.

  2. Avoid using functions such as showUser(post) to introduce JSX elements into render method. Direclty introduce it into the component as follows.

        {posts.map((post) => (
          <div>
            <div
              class="card bg-light mb-3 offset-md-4"
              style={{ width: "30rem" }}
            >
              <div class="card-body">
                <Link to={{ pathname: "/UserDetail", state: { post } }}>
                  <h5 class="card-title">
                    {post.userDetails != undefined ? post.userDetails.name : ""}
                  </h5>
                </Link>
                <p class="card-text">{post.emailAddress}</p>
                <p class="card-text">
                  {post.userDetails != undefined ? post.userDetails.phone : ""}
                </p>
              </div>
            </div>
          </div>
        ))}
  1. Create react components in a reusable format. (Even I have duplicated the card component details in Users and UserDetail component. It's better to have separate child component as CardDetails to reuse it)