Display Component on click over another Component ReactJS - javascript

I have Menu component. I'm adding items to Cart component by clicking on Add to Cart button.
I also have a Cart icon which holds array of items in Cart.
const Menu = () => {
const [cart, setCart] = useState([]);
const addToCart = (el) => setCart( [...cart, el]);
console.log(cart);
return (
<>
<Tabs className="tabs-wrapper" id="menu">
<TabList className="tabs">
<Tab className="tab-item">Burgers</Tab>
<Tab className="tab-item">Lunch of the day</Tab>
<Tab className="tab-item">Crepes</Tab>
</TabList>
<TabPanel>
<div className="burgers">
<ul>
{burgers.map(burger => (
<li key={burger.id}>
<h4>{burger.title}</h4>
<span>{burger.price}</span>
<img src={burger.image} alt={burger.title} />
<p>{burger.description}</p>
<button type="submit" onClick={() => addToCart(burger, "burger")}>Add to cart</button>
</li>
))}
</ul>
</div>
</TabPanel>
<TabPanel>
<div className="lunch">
<h4>Sweet lunch today!</h4>
<span>7$</span>
<p>You can choose one of our 3 sweet crepes + one of our 4 cold drinks!
<br />
Nutella crepe, Crepe with salted caramel and nuts or Oreo Bang crepe with whipped cream and raspberries.
<br />
For drink - one of our homemade lemonades - Melon, Orange or Lemon-Mint. Or a Frozen Coffee!
</p>
<div>
<img src={sweetLunch} alt="Sweet crepe lunch" />
<img src={sweetCrepes} alt="Sweet crepes lunch" />
</div>
</div>
</TabPanel>
<TabPanel>
<div className="crepes">
<ul>
{crepes.map(crepe => (
<li key={crepe.id}>
<h4>{crepe.title}</h4>
<span>{crepe.price}</span>
<img src={crepe.image} alt={crepe.title} />
<p>{crepe.description}</p>
<button type="submit" onClick={() => addToCart(crepe, "crepe")}>Add to cart</button>
</li>
))}
</ul>
</div>
</TabPanel>
</Tabs>
<FontAwesomeIcon className="cart" icon={["fas", "shopping-cart"]} onClick={() => setCart(cart)}/>
</>
)
}
I want to make Cart component appear above Menu component, display on the right side and take a half of screen(like on Upwork when you click on jod in feed) when I click on Cart icon.
So I tried to import Cart component (which also holds a Form) into Menu component
const Cart = ({ cart }) => {
const { image, title, price } = cart;
return (
<>
<li>
<img src={image} alt={title} />
<h4>{title}</h4>
<span>{price}</span>
</li>
<Form />
</>
)
}
and got
TypeError: Cannot destructure property 'image' of 'cart' as it is undefined.
at Cart (Cart.jsx:6)
My App.jsx looks like this
import React, { useState } from "react";
import {
BrowserRouter as Router,
Route,
Switch,
Redirect
} from "react-router-dom";
import './App.css';
import './Responsive.css';
const Header = React.lazy(() => import("./components/Header"));
const Footer = React.lazy(() => import("./components/Footer"));
const Home = React.lazy(() => import("./components/Home"));
const Menu = React.lazy(() => import("./components/Menu"));
function App() {
const [cart, setCart] = useState([]);
return (
<Router>
<React.Suspense fallback={<p className="loader">Loading...</p>}>
<Header />
<Switch>
<Route path="/home" render={props => <Home {...props} />} />
<Route path="/menu" render={props => <Menu cart={cart} {...props} />} />
<Route exact path="/">
<Redirect to="/home" />
</Route>
</Switch>
<Footer/>
</React.Suspense>
</Router>
);
}
export default App;

props which you try to pass is an empty table
const [cart, setCart] = useState([]);
<Menu cart={cart} />

After some restructuring I managed to find an answer for displaying cart items
{cart.map((el) => (
<Cart
key={el.id}
product={el}
removeFromCart={removeFromCart}
/>
))}
And Cart component itself
export default function Cart ({ product, removeFromCart }) {
const { image, title, price } = product;

Related

Routes working fine but not rendering components

I am routing between child components in a parent component. Routes are working fine on click but the child components are not rendering on page. No errors in console. No errors in code according to ChatGPT.
I resolved every issue but components do not render on page even route is working fine in url and there are no errors in console.
App.js
import './App.css';
import Navbar from './components/Navbar';
import { Routes, Route } from 'react-router-dom';
import NewOrder from './components/NewOrder';
import Orders from './components/Orders';
function App() {
return (
<>
<Navbar />
<Routes>
<Route path='/newOrder/*' element={<NewOrder />} />
<Route exact path='/orders' element={<Orders />} />
</Routes>
</>
);
}
export default App;
NewOrder.jsx
import React from 'react'
import { Link, Route, Routes } from 'react-router-dom'
import ChooseBun from './ChooseBun.jsx'
import ChooseFillet from './ChooseFillet.jsx'
import './NewOrder.css'
const NewOrder = () => {
return (
<>
<div className='container'>
<h1>Make Your Own Burger!</h1>
<ul>
<li>
<Link to="/newOrder/choose-bun">Child 1</Link>
</li>
<li>
<Link to="/newOrder/choose-meat">Child 2</Link>
</li>
</ul>
{/* <ChooseBun/> */}
<Routes>
<Route path='/newOrder/choose-bun' element={<ChooseBun />} />
<Route path='/newOrder/choose-meat' element={<ChooseFillet />} />
</Routes>
</div>
</>
)
}
export default NewOrder
Child1 which is ChooseBun.jsx
import React, { useEffect, useRef, useState } from 'react'
import './NewOrder.css'
import bun1 from '../images/front-view-tasty-meat-burger-with-cheese-salad-dark-background.jpg'
import { useNavigate } from 'react-router-dom'
const ChooseBun = () => {
const ref = useRef(null);
const [selectImage, setSelectImage] = useState('');
const [select, setSelect] = useState(false);
const handleImageClick = (id) => {
setSelectImage(id);
setSelect(true);
};
useEffect(() => {
const handleClickOutside = (e) => {
if (ref.current && !ref.current.contains(e.target)) {
setSelectImage('');
setSelect(false);
}
};
document.addEventListener("mousedown", handleClickOutside);
return () => document.removeEventListener("mousedown", handleClickOutside);
}, []);
let navigate = useNavigate();
return (
<>
<div className="choose-bun">
<h2>Choose Your Bun</h2>
<div ref={ref}>
<div className='mainContainer mt-5'>
<img
src={bun1}
alt="Brioche Bun"
className={`col-3 ${selectImage === 'img1' ? 'selected' : ''}`}
onClick={() => handleImageClick('img1')}
/>
<img
src={bun1}
alt="Brioche Bun"
className={`col-3 ${selectImage === 'img2' ? 'selected' : ''}`}
onClick={() => handleImageClick('img2')}
/>
<img
src={bun1}
alt="Brioche Bun"
className={`col-3 ${selectImage === 'img3' ? 'selected' : ''}`}
onClick={() => handleImageClick('img3')}
/>
</div>
<div className='mainContainer mt-5'>
<img
src={bun1}
alt="Brioche Bun"
className={`col-3 ${selectImage === 'img4' ? 'selected' : ''}`}
onClick={() => handleImageClick('img4')}
/>
<img
src={bun1}
alt="Brioche Bun"
className={`col-3 ${selectImage === 'img5' ? 'selected' : ''}`}
onClick={() => handleImageClick('img5')}
/>
<img
src={bun1}
alt="Brioche Bun"
className={`col-3 ${selectImage === 'img6' ? 'selected' : ''}`}
onClick={() => handleImageClick('img6')}
/>
</div>
</div>
<button
className='btn btn-danger'
disabled={!select}
onClick={() => navigate('/newOrder/choose-meat')}
>
Next
</button>
</div>
</>
);
};
export default ChooseBun
I Edit your App.jsx to : wrap your Routes with BrowserRouter :
function App() {
return (
<>
<BrowserRouter>
<Navbar />
<Routes>
<Route path='/newOrder' element={<NewOrder />} >
<Route path='choose-bun' element={<ChooseBun />} />
<Route path='choose-meat' element={<ChooseFillet />} />
</Route>
<Route exact path='/orders' element={<Orders />} />
</Routes>
</BrowserRouter>
</>
);
}
export default App;
ChoosenFillet And ChooseBun are child of NewOrder. for access them in NewOrder, use Outlet
NewOrder.jsx :
import { Outlet } from 'react-router-dom';
const NewOrder = () => {
return (
<>
<div className='container'>
<h1>Make Your Own Burger!</h1>
<ul>
<li>
<Link to="/newOrder/choose-bun">Child 1</Link>
</li>
<li>
<Link to="/newOrder/choose-meat">Child 2</Link>
</li>
</ul>
{/* <ChooseBun/> */}
<Outlet />
</div>
</>
)
}
Descendent routes in a Routes component build their paths relative to the parent route. The issue is that in the NewOrder component the routes will be relative from the parent "/newOrder/*" route path. In other words, the paths are actually "/newOrder/newOrder/choose-bun" and "/newOrder/newOrder/choose-meat".
You should omit the leading "/newOrder" prefix from the descendent routes.
const NewOrder = () => {
return (
<>
<div className="container">
<h1>Make Your Own Burger!</h1>
<ul>
<li>
<Link to="/newOrder/choose-bun">Child 1</Link>
</li>
<li>
<Link to="/newOrder/choose-meat">Child 2</Link>
</li>
</ul>
{/* <ChooseBun/> */}
<Routes>
<Route path="/choose-bun" element={<ChooseBun />} />
<Route path="/choose-meat" element={<ChooseFillet />} />
</Routes>
</div>
</>
);
};

Cannot render data from API being passed from parent to child (ReactJS)

I just tried to follow this question with no results for me.
The point is that I'm trying to get a selected pokemon from a component and pass down to another component. The data is correctly passed, some data are displayed, but with other (for example, the sprites) I got an error. I'm using Context by the way.
PokemonContext.js
import React, { useState } from 'react';
const Context = React.createContext({});
export function PokemonsContextProvider({ children }) {
const [favorites, setFavorites] = useState([]);
return <Context.Provider value={{ favorites, setFavorites }}>{children}</Context.Provider>;
}
export default Context;
App.js
<PokemonsContextProvider>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/pokemons" element={<PokemonsList />} />
<Route path="/favorites" element={<Favorite />} />
<Route path="/pokemon/:name" element={<PokemonDetails />} />
<Route path="*" element={<NotFound />} />
</Routes>
</PokemonsContextProvider>
PokemonsDetails.js
const PokemonDetails = () => {
const { name } = useParams();
const [pokemon, setPokemon] = useState('');
useEffect(() => {
pokemonService.pokemonDetail(name).then((res) => {
setPokemon(res);
});
}, []);
return (
<div>
<h1 className="text-center mb-4">Details for {name.toUpperCase()}</h1>
<PokemonCard pokemon={pokemon} />
<div className="text-center">
<Link className="btn btn-success mx-2 my-4" to="/favorites">
Go back
</Link>
</div>
</div>
);
};
PokemonCard.js
const PokemonCard = ({ pokemon }) => {
return (
<div className="card text-center bg-primary">
<div className="card-body">
<h5 className="card-title">{pokemon.name}</h5>
</div>
<ul className="list-group list-group-flush">
<li className="list-group-item">Weight: {pokemon.weight}</li>
<li className="list-group-item">Height: {pokemon.height}</li>
</ul>
</div>
);
};
export default PokemonCard;
When I add this line <img className="card-img-top" src={pokemon.sprites.front_default} alt="Card image cap" /> to the PokemonCard component I got this error:
The data is correctly displayed when I console log it, so, I don't know why I'm having this error. If I inspect the React Dev Tools the data is in the component!
The PokemonCard.js component is being rendered before the result of the request.
You can resolve this problem checking if there is a pokemon before use his props.
const PokemonCard = ({ pokemon }) => {
return pokemon && (
<div className="card text-center bg-primary">
<img className="card-img-top" src={pokemon.sprites?.front_default} alt="Card image cap" />
<div className="card-body">
<h5 className="card-title">{pokemon.name}</h5>
</div>
<ul className="list-group list-group-flush">
<li className="list-group-item">Weight: {pokemon.weight}</li>
<li className="list-group-item">Height: {pokemon.height}</li>
</ul>
</div>
);
};
export default PokemonCard;

How to pass an array object from a component to a page in reactjs

Child
import React from "react";
import { Link } from "react-router-dom";
import "../pages/All.css";
const MovieList = (props) => {
return(
<>
{props.movies.map((movie, index) => (
<div className="ro">
<img src={movie.Poster} alt={movie.Title} /> <br /> <br />
<label>{movie.Title}</label> <br />
<p>{movie.Type} {movie.Year}</p> <br /> <br />
<div className="overlay">
<li><Link to = "/play" class="popup-video btn">Watch</Link></li>
<li><Link to ="movie-details.html" class="btn">Download</Link></li>
</div>
</div>
))}
</>
);
};
export default MovieList;
import React from "react";
import ReactPlayer from "react-player";
function Play(movie){
return(
<div>
<ReactPlayer width="100%" height="750px" controls url ={"http://www.youtube.com/"+movie.Title} />
</div>
);
}
export default Play;
i am trying to pass {movie.Title} to controls url in Parent Component
I hope what you want to ask is how to pass params.
const MainNavigation = ()=> (
<Routes>
<Route path="/" element={<VideoList />} />
<Route path="/play:id" element={<Play />} />
</Routes>
)
const VideoList = ()=> (
<Link to={"/play/" + movie.title}>{movie.title}</Link>
)
const Play = ()=> {
const {id} = useParams();
return (
<VideoComponent url={"https://example.com/" + id} />
)
}
For more information, read official documents. https://reactrouter.com/docs/en/v6/hooks/use-params

I want to pass an image as a prop to another page

The main problem is that this image is selected from the file explorer and I am using react-router.
Add.js
this is where you select the image
import { Link } from "react-router-dom";
import About from "./About";
import './styles/modal.css'
import firebase from "firebase";
require("firebase/firestore")
require("firebase/storage")
export default function Add(props) {
const [image, setImage] = useState(null);
const [modal, setModal] = useState(false);
const pickImage = (event) => {
//console.log();
setImage(URL.createObjectURL(event.target.files[0]));
//console.log(image);
}
const toggle = () => {
setModal(!modal);
}
return (
<div>
<h1>Add</h1>
<button onClick={toggle}>Add image</button>
{modal ? (
<div className="modal-bg">
<div className="modal">
<img src={image} style={{ width: '60%', height: '60%' }} className="ex-img" />
<br /><br />
<label htmlFor="fie" className="gcoo btn-default">+ File
<input id="fie" type="file" onChange={pickImage} className="file-pick" />
</label>
<br />
<br />
<div className="bottom-buttons">
<Link to="/about">
<button className="save">Save</button>
</Link>
<button onClick={() => setModal(false)} className="closse">Close</button>
</div>
</div>
</div>
) : null}
</div>
)
}
I am using firebase but not in this file so you can ignore this.
MainRoutes.js
this is where all the routes and pages are.
import { Route } from "react-router";
import { Switch } from 'react-router-dom';
import ImageDisplay from "./components/ImageDisplay";
import Add from './components/Add';
export default function MainRoute(props) {
return (
<Switch>
<Route exact path="/about" component={() => <ImageDisplay />} />
<Route exact path="/add" component={() => <Add />} />
</Switch>
);
}
finally this file ImageDisplay.js is where the image should be displayed
I dont have much on this file because i dont know how to put in any images.
I have tried props but whenever i imported the Imagedisplay it always showed the content on it and i dont want anything from image display. I only want to send an image over there.
import React from 'react'
import { Link } from "react-router-dom"
function ImageDisplay(props) {
return (
<div>
<h1>image</h1>
<div>
<img />
<p></p>
</div>
</div>
)
}
export default ImageDisplay;
Make sure that you are not reloading the page when moving between the two routes, since this will remove all state.
To share state between the two components you would need to store the state in the parent, and pass it to the children.
Add:
export default function Add(props) {
const pickImage = (event) => {
props.setImage(URL.createObjectURL(event.target.files[0]));
}
// The rest of your function
}
And in your parent:
export default function MainRoute(props) {
const [image, setImage] = useState(null)
return (
<Switch>
<Route exact path="/about" component={() => <ImageDisplay image={image} />} />
<Route exact path="/add" component={() => <Add setImage={setImage} />} />
</Switch>
);
}
You can now access the image prop in your imageDisplay.
function ImageDisplay(props) {
return (
<div>
<h1>image</h1>
<div>
<img src={props.image} />
<p></p>
</div>
</div>
)
}

How to pass selected items data to another component React

I have a Menu component, which displays my Menu items. I also have here function addToCart and Cart icon. Function addToCart works fine and store array of selected items.
const Menu = () => {
const [cart, setCart] = useState([]);
const addToCart = (el) => setCart( [...cart, el]);
console.log(cart);
return (
<>
<Tabs className="tabs-wrapper" id="menu">
<TabList className="tabs">
<Tab className="tab-item">Burgers</Tab>
<Tab className="tab-item">Lunch of the day</Tab>
<Tab className="tab-item">Crepes</Tab>
</TabList>
<TabPanel>
<div className="burgers">
<ul>
{burgers.map(burger => (
<li key={burger.id}>
<h4>{burger.title}</h4>
<span>{burger.price}</span>
<img src={burger.image} alt={burger.title} />
<p>{burger.description}</p>
<button type="submit" onClick={() => addToCart(burger.title, "burger")}>Add to cart</button>
</li>
))}
</ul>
</div>
</TabPanel>
<TabPanel>
<div className="crepes">
<ul>
{crepes.map(crepe => (
<li key={crepe.id}>
<h4>{crepe.title}</h4>
<span>{crepe.price}</span>
<img src={crepe.image} alt={crepe.title} />
<p>{crepe.description}</p>
<button type="submit" onClick={() => addToCart(crepe.title, "crepe")}>Add to cart</button>
</li>
))}
</ul>
</div>
</TabPanel>
</Tabs>
<FontAwesomeIcon className="cart" icon={["fas", "shopping-cart"]}/>
</>
)
}
How to pass these items info to Cart component, which I want to open on Cart icon click? Also I would like to avoid router if it's possible.
Edit:
How to make Cart component show image,title and price properties of items, added to a Cart?
const Cart = (props) => {
return (
<>
<div>
<img src={props.image} alt={props.title} />
<h4>{props.title}</h4>
<span>{props.price}</span>
</div>
<Form/>
</>
)
}
You can pass cart with other props to CartComponent.
<CartComponent cart={ cart }/>
If your CartCompoennt is outside menu you should bring your cart state up in that way to by able pass them where you need.
function App() {
const [cart, setCart] = useState([]);
const addToCart = (el) => setCart( [...cart, el]);
return (
<div>
<CartComponent cart={ cart }/>
<Menu cart={ cart } addToCart={ addToCart } />
</div>
)
}

Categories