Muneeba Dilawaze
Muneeba Dilawaze

Reputation: 115

React Routers not working on button click

I am making a food app that when the button on each component is it open on another page and the URL also changes .so I am using react routers but when I click the button it does not open that component

This is App.js

import React from "react";
import "bootstrap/dist/css/bootstrap.min.css";
import "./App.css";
import {
  BrowserRouter as Router,
  Switch,
  Route,
  Link
} from "react-router-dom";
import About from "./About"
import Contact from "./Contact"
import Home from "./Home"
import Menu from "./Menu"
function App() {

  return (
    <div>
      <div>
        <div className="navbar">
          <h3>Food Festive</h3>
          <div>
            <ul>
              <li>
                <Link className="chg" to="/home">Home</Link>
              </li>
              <li>
                <Link className="chg" to="/about">About</Link>
              </li>
              <li>
                <Link className="chg" to="/contact">Contact</Link>
              </li>
              <li>
                <Link className="chg" to="/menu">Menu</Link>
              </li>
            </ul>
          </div>
        </div>

        <Switch>

          <Router path="/home">
            <Home />
          </Router>
          <Router path="/about">
            <About />
          </Router>
          <Router path="/contact">
            <Contact />
          </Router>
          <Router path="/menu">
            <Menu />
          </Router>
        </Switch>
      </div>
    </div>
  );
}

export default App;


the CardItems.js here I want that when I click Button it opens ButtonClick.js separately. but when I click it it displays after the button like this:enter image description here

import React from "react";
import { Card, Button, CardDeck } from "react-bootstrap";
import "bootstrap/dist/css/bootstrap.min.css";
import "./App.css";
import ButtonClick from "./ButtonClick"
import {
  BrowserRouter as Router,
  Switch,
  Route,
  Link
} from "react-router-dom";

function CardItems(props) {
  function name() {
    console.log(`${props.item.name}`)
  }
  return (
    <div className="wrap">
      <Card>
        <Card.Img variant="top" src={require(`${props.item.img}`)} />
        <Card.Body>
          <h5>{props.item.name}</h5>
          <div>
            <h6>Price : ${props.item.price} </h6>
            <h6>Orders till now : {props.item.Orders} </h6>
            <h6>Home Delivery Time : {props.item.Delivery} </h6>
            <h6>Quantity : {props.item.Quantity}</h6>
          </div>
          <Link to="/newpage">
            <Button variant="info" onClick={name}>
              Details
          </Button>
          </Link>

          <Switch>
            <Router path="/newpage">
              <ButtonClick />
            </Router>
          </Switch>

        </Card.Body>
      </Card >
    </div>
  );
}

export default CardItems;

CardItems array

const CardItemsArray = [
  {
    id: 1,
    img: "./images/Food/cupcakes.jpg",
    name: "Cupcakes",
    price: 20,
    Orders: 3025,
    Delivery: "45mins",
    Quantity: "6 Cup-cakes",
  },

  {
    id: 2,
    img: "./images/Food/fried-chicken.jpg",
    name: "Fried Chicken",
    price: 30,
    Orders: 3001,
    Delivery: "45mins",
    Quantity: "3 Pieces",
  },

  {
    id: 3,
    img: "./images/Food/pizza23.jpg",
    name: "Pizza",
    price: 50,
    Orders: 5029,
    Delivery: "45mins",
    Quantity: "1 Pizza",
  },

  {
    id: 4,
    img: "./images/Food/instant-nood.jpg",
    name: "Instant Noodles",
    price: 10,
    Orders: 1042,
    Delivery: "45mins",
    Quantity: "1 Plate",
  },

  {
    id: 5,
    img: "./images/Food/hamburger.jpg",
    name: "Hamburger",
    price: 40,
    Orders: 2134,
    Delivery: "45mins",
    Quantity: "1 Burgur",
  },
  {
    id: 6,
    img: "./images/Food/sushi.jpg",
    name: "Shushi",
    price: 100,
    Orders: 1872,
    Delivery: "45mins",
    Quantity: "1 Plate",
  },

  {
    id: 7,
    img: "./images/Food/ice.jpg",
    name: "Ice-Cream",
    price: 10,
    Orders: 1272,
    Delivery: "45mins",
    Quantity: "1 Cup",
  },

  {
    id: 8,
    img: "./images/Food/chicken-stack.jpg",
    name: "Beef Steack",
    price: 70,
    Orders: 2381,
    Delivery: "45mins",
    Quantity: "1 Piece",
  },

  {
    id: 9,
    img: "./images/Food/fries.jpg",
    name: "Fries",
    price: 15,
    Orders: 4231,
    Delivery: "45mins",
    Quantity: "1 Pack",
  },

  {
    id: 10,
    img: "./images/Food/ice-cups.jpg",
    name: "Ice-Cream-Cups",
    price: 20,
    Orders: 2836,
    Delivery: "45mins",
    Quantity: "2 Cups",
  },
  {
    id: 11,
    img: "./images/Food/strawb-smo.jpg",
    name: "Strawberry Smoothie",
    price: 30,
    Orders: 2981,
    Delivery: "45mins",
    Quantity: "1 Glass",
  },

  {
    id: 12,
    img: "./images/Food/salad2.jpg",
    name: "Salad",
    price: 20,
    Orders: 2311,
    Delivery: "45mins",
    Quantity: "1 Plate",
  },

  {
    id: 13,
    img: "./images/Food/orange juice.jpg",
    name: "Orange Juice",
    price: 15,
    Orders: 1637,
    Delivery: "45mins",
    Quantity: "1 Glass",
  },

  {
    id: 14,
    img: "./images/Food/fruits-beauti.jpg",
    name: "Fruit Salad",
    price: 30,
    Orders: 1091,
    Delivery: "45mins",
    Quantity: "1 Plate",
  },

  {
    id: 15,
    img: "./images/Food/tea1.jpg",
    name: "Ice Tea",
    price: 20,
    Orders: 2348,
    Delivery: "45mins",
    Quantity: "1 Cup",
  },
  {
    id: 16,
    img: "./images/Food/tea2.jpg",
    name: "Mint Tea",
    price: 20,
    Orders: 2536,
    Delivery: "45mins",
    Quantity: "1 Cup",
  },
  {
    id: 17,
    img: "./images/Food/bread.jpg",
    name: "Bread Cuisine",
    price: 40,
    Orders: 975,
    Delivery: "45 mins",
    Quantity: "1 Plate",
  },
  {
    id: 18,
    img: "./images/Food/lime-juice.jpg",
    name: "Lime Juice",
    price: 20,
    Orders: 6437,
    Delivery: "45 mins",
    Quantity: "1 Glass",
  },
  {
    id: 19,
    img: "./images/Food/pizza2.jpg",
    name: "Fagita Pizza",
    price: 100,
    Orders: 1862,
    Delivery: "45 mins",
    Quantity: "1 Pizza",
  },
  {
    id: 20,
    img: "./images/Food/cake2.jpg",
    name: "Cake",
    price: 150,
    Orders: 2154,
    Delivery: "45 mins",
    Quantity: "1 Cake",
  },
];

export default CardItemsArray;


menu.js

import React from "react";
import CardItems from "./CardItems.js";
import CardItemsArray from "./CardItemsArray";

function Menu() {
    const items = CardItemsArray.map((item) => (
        <CardItems key={item.id} item={item} />
    ));
    return (
        <div>
            <div>{items}</div>
        </div>
    );
}

export default Menu;

ButtonClick.js

import React from "react";

function ButtonClick(props) {
  return (
    <div>
      <h1>Button is Clicked</h1>
    </div>
  );
}
export default ButtonClick;


Upvotes: 4

Views: 666

Answers (3)

Asad S
Asad S

Reputation: 2116

I think you have been using React Router the wrong way.

Here is 3 tips to get started with React Router:

  1. Only use 1 (one) Router Component in your app, which should be located in the top level. (It is BrowserRouter, but you renamed it into Router in your import)

  2. Use Route Component (not Router) to declare available route in your application. For simple use case, better to just use it like this: <Route path="/thePath" component={ComponentName} />

  3. Use Link Component (while specifying to="/routeName" props) to go to any desired route. Like this: <Link to="/thePath"><button>Go to a certain route</button></Link>

  4. Bonus. You may not need Switch Component. It should be used in advanced case where you need to only render the first child route that matches and do not render other routes even though they also match.

You want to go to ButtonClick.js in a separate screen right? You need to add it into your route. So in your case, it should be like this:

In app.js

import React from "react";
import "bootstrap/dist/css/bootstrap.min.css";
import "./App.css";
import {
  BrowserRouter as Router,
  Switch,
  Route,
  Link
} from "react-router-dom";
import About from "./About"
import Contact from "./Contact"
import Home from "./Home"
import Menu from "./Menu"
import ButtonClick from "./ButtonClick"

function App() {

  return (
   // HERE, add Router to the top level of your app.
   // Refer to tip number 1.
    <Router>
      <div>
        <div className="navbar">
          <h3>Food Festive</h3>
          <div>
            <ul>
              <li>
                <Link className="chg" to="/home">Home</Link>
              </li>
              <li>
                <Link className="chg" to="/about">About</Link>
              </li>
              <li>
                <Link className="chg" to="/contact">Contact</Link>
              </li>
              <li>
                <Link className="chg" to="/menu">Menu</Link>
              </li>
            </ul>
          </div>
        </div>

        // HERE, don't use Router, but use Route.
        // Refer to tip number 2.
        <Route path="/home" component={Home} />
        <Route path="/about" component={About} />
        <Route path="/contact" component={Contact} />
        <Route path="/menu" component={Menu} />

        // HERE, add this line below. Refer to tip number 2. 
        // You should add any routes available in your app using the Route component.
        // With this code you are saying:
        // If the path is equal to /button-click, please render the ButtonClick component.
        <Route path="/button-click" component={ButtonClick} />
        
      </div>
    </Router>
  );
}

export default App;

And in your CardItems.js (Actually, I just guess the name of this file)

import React from "react";
import { Card, Button, CardDeck } from "react-bootstrap";
import "bootstrap/dist/css/bootstrap.min.css";
import "./App.css";
import ButtonClick from "./ButtonClick"
import {
  BrowserRouter as Router,
  Switch,
  Route,
  Link
} from "react-router-dom";

function CardItems(props) {
  function name() {
    console.log(`${props.item.name}`)
  }
  return (
    <div className="wrap">
      <Card>
        <Card.Img variant="top" src={require(`${props.item.img}`)} />
        <Card.Body>
          <h5>{props.item.name}</h5>
          <div>
            <h6>Price : ${props.item.price} </h6>
            <h6>Orders till now : {props.item.Orders} </h6>
            <h6>Home Delivery Time : {props.item.Delivery} </h6>
            <h6>Quantity : {props.item.Quantity}</h6>
          </div>

          // HERE, make sure your button is wrapped with Link component, supply it with its corresponding "to" props. 
          // Refer to tip number 3.
          // With this code, you are saying:
          // If anyone clicks this button, redirects them into /button-click route.
          // And because we have set this route in app.js, the user will see the ButtonClick component.
          <Link to="/button-click">
            <Button variant="info" onClick={name}>
              Details
            </Button>
          </Link>

          // And over here, you don't need any Switch.

        </Card.Body>
      </Card >
    </div>
  );
}

export default CardItems;

Thats it! Hope it helps. Let me know if you still bumped into errors.

PS: I haven't run this code, I just edit it here in StackOverflow, it may contain some syntax error. But I tried my best to not let any error be in your way :) I know the comments will be error tho, as comments inside JSX is a bit complicated, like this { /* commented code */ }. I just too lazy to do that, so I just use simple double slash. You can just delete it in your code, after you understood it.

Upvotes: 1

Pavlos Karalis
Pavlos Karalis

Reputation: 2966

See sandbox for working example:

https://codesandbox.io/s/hidden-worker-lxqbz?file=/src/App.js

Notes:

  • Router should wrap around App in index.js
  • Route (not Router) is what directs paths inside a switch and written as
<Route path="/path_name" render={() => <Component />} />
  • map nav routes rather than hard code for readability
  • don't make your ids linear, it well mess with React's tracking ability
  • within cardItem, if you're trying to get Link to open a new page it should be
 <Link to={`/item/${item.id}`}>
  • then add route within the app switch
<Route path="/item/:id" render={() => <Item />} />
  • in that Item component, find item in data by url param

Upvotes: 1

rexess
rexess

Reputation: 755

The reason for this behavior is that the route you have set up for the new page exists within the same component.

I have identified two options you could undertake to achieve the desired behavior:

  1. Add a Router at the top level of the application in your App.js file that has a has path="/newpage and child component, <ButtonClicked/>. The link that points to this new page stays the same i.e it has to="/newpage".

OR

  1. Modify the routes within your Menu.js file to have two different routes. The first Router will have path=${this.props.match.path}, which should display your menu items when accessed, and the second Router will have path=${this.props.match.path}/newpage. Equally, the Link that points to the new page should have prop to=${this.props.match.path}/newpage. This should display the new page.

Also, here is a link to the documentation for the match prop offered with React Router. I believe it is accessible to each component rendered through a Router.

Here is your Menu.js file modified according to the 2nd option. Hope it helps!

import React from "react";
import { Card, Button, CardDeck } from "react-bootstrap";
import "bootstrap/dist/css/bootstrap.min.css";
import "./App.css";
import ButtonClick from "./ButtonClick"
import {
  BrowserRouter as Router,
  Switch,
  Route,
  Link
} from "react-router-dom";

function CardItems(props) {
  function name() {
    console.log(`${props.item.name}`)
  }
  
  function showCard(){
    return (
      <Card>
        <Card.Img variant="top" src={require(`${props.item.img}`)} />
        <Card.Body>
          <h5>{props.item.name}</h5>
          <div>
            <h6>Price : ${props.item.price} </h6>
            <h6>Orders till now : {props.item.Orders} </h6>
            <h6>Home Delivery Time : {props.item.Delivery} </h6>
            <h6>Quantity : {props.item.Quantity}</h6>
          </div>
          <Link to=`${this.props.match.path}/newpage`>
            <Button variant="info" onClick={name}>
              Details
            </Button>
          </Link>
        </Card.Body>
      </Card >
    )
  }
  
  return (
    <div className="wrap">
          <Switch>
            <Router path=`${this.props.match.path}/`>
              {showCard()}
            </Router>
            <Router path=`${this.props.match.path}/newpage`>
              <ButtonClick />
            </Router>
            <Router path=`${this.props.match.path}/newpage`>
              Page not found
            </Router>
          </Switch>
    </div>
  );
}

export default CardItems;

Upvotes: 1

Related Questions