I'm currently trying to implement a e-commerce project. My question is about Context API and Reducer.
Cannot able to render price and other details of the product. in Cart Component
Context.Js ;
Here is my Context.js
Reducer.JsHere is the Reducer.js
And My Product Component Code is ;
import './Product.css'
import AddBoxIcon from '#material-ui/icons/AddBox';
import { Context } from "./Context"
import React, {useContext} from "react"
function Product({title,price,image,id}) {
const {addtoBasket} = useContext(Context)
/*
function alertUser() {
alert(`${title} added to your card`)
}
function addBasket(){
console.log(title,price)
}
function firedFunctions(){
alertUser()
addBasket()
}
*/
return (
<div className="product">
<div className="product__info">
<img src={image} alt=""></img>
<p className="title">{title}</p>
<div className ="price__add" >
<h4>Price : {price} $</h4>
<div onClick={() => addtoBasket(title, price, image,id)}>
<AddBoxIcon className="btn" />
</div>
</div>
</div>
</div>
)
}
export default Product
And My Cart Component Code is ;
import React, {useContext} from 'react'
import './Cart.css'
import {Context} from "./Context"
import Product from "./Product"
function Cart() {
const {basket} = useContext(Context)
console.log(basket) // Expected: Empty Array
return (
<div className="cart">
<div className="cart__left">
<h2>Your Products</h2>
<div>
{basket.map((product) =>(
<h4>{product}</h4>
{/*why product give me just a title of product*/}
))}
</div>
</div>
<div className="cart__right">
<h2>Total</h2>
</div>
</div>
)
}
export default Cart
And this is the output when i click the button v.1(console) ;
I want to see Price and image either.
You are passing three parameters to addToBasket function, however it is receiving just one object.
Probably what you needs is:
<div onClick={() => addtoBasket({title, price, image, id)}>
I've just replicate it in codesandbox, this is the right answer, take a look:
https://codesandbox.io/s/awesome-violet-fr7np?file=/src/index.js
Related
build this part of the code with useState initially and everything worked perfectly but I need to share this state with my main component (no relationships between those two) and decided to use Redux but def something is wrong, any ideas?
Here's the console error:
MUI: The value provided to the Tabs component is invalid.
None of the Tabs' children match with "-1".
You can provide one of the following values: 0, 1, 2.
import { React } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import '../../css/SideBar.css';
import { UilSignOutAlt } from '#iconscout/react-unicons';
import Logo from '../../../../assets/img/companyLogo.jpg';
import { SidebarData } from '../../Data/Data';
import { setDashboard } from '../../../../app/actions';
function SideBar() {
const selected = useSelector((state) => state.dashboard);
const dispatch = useDispatch();
return (
<div className="Sidebar">
{/* logo */}
<div className="logo">
<img src={Logo} alt="logo" />
<span>Company Name</span>
</div>
{/* menu */}
<div className="menu">
{SidebarData.map((item, index) => (
/* eslint-disable */
<div
role='menu'
className={selected === index ? 'menuItem active' : 'menuItem'}
key={index}
onClick={() => dispatch(setDashboard(index))}
onKeyDown={() => dispatch(setDashboard(index))}
>
<item.icon />
<span>{item.heading}</span>
</div>
))}
<div className='menuItem'>
<UilSignOutAlt />
</div>
</div>
</div>
);
}
export default SideBar;
I am trying to implement react pagination on local json data, using react-paginate. The buttons are clickable and the css works fine. However, any components after the first page are not being rendered. The entire page (except for the header) goes blank. The pagination buttons were the only components visible at first, but once I applied some styling to the buttons, they vanished as well (just basic styling like background colours etc). Now nothing is displayed unless I'm on the first page of cards displayed. Can you please help me with this issue?
This is my dashboard.tsx
import React, { useState } from 'react'
import logo from '../assets/logo192.png'
import courses from '../data/courses.json'
import star_on from '../assets/star_on.png'
import star_off from '../assets/star_off.png'
import next from '../assets/next.png'
import left_arrow from '../assets/left-arrow.png'
import right_arrow from '../assets/right-arrow.png'
import ReactPaginate from 'react-paginate'
function Dashboard(this: any) {
let on = false
const turnOn = (event: any) => {
if (on)
{event.target.src = star_off
on = false
}
else {
event.target.src = star_on
on = true
}
}
const [cards, setCards] = useState(courses)
const [pageNumber, setPageNumber] = useState(0)
const cardsPerPage = 6
const pagesVisited = pageNumber * cardsPerPage
const displayCards = cards
.slice(pagesVisited, pagesVisited + cardsPerPage)
.map(card => {
return (
<div className='dashboard--card'>
<div className='line1'>
<div><img src ={card.image} alt ="course" className='card--image'></img></div>
<div className='card--title'>{card.title}</div>
<div className='card--author'>{card.author}</div>
<div> <img className='card--star' src={star_off} alt="star" onClick={turnOn} /></div>
<div className='card--price'>Rs {card.price}/-</div>
<div className='card--discounted'>Rs {card.discounted}/-</div>
<div className='card--cartbtn'> ADD TO CART</div>
<img className='card--arrow' src ={next} alt ="arrow"/>
</div>
<div className='line2'>
<div className='reactbtn'>React</div>
<div className='reactbtn'>React</div>
</div>
</div>
)
})
const pageCount = Math.ceil(cards.length / cardsPerPage)
const changePage = (selected: React.SetStateAction<number>) => {
setPageNumber(selected)
}
return (
<div className='dashboard--main'>
<div className='dashboard--banner'>
<div className='dashboard--banner-title'>
Discover Latest Courses on React
</div>
<div className='dashboard--banner-logo'>
<img src={logo} alt ="react-logo" className='react-logo'/>
</div>
</div>
<div className='dashboard--items'>
<div className='dashboard--left'>
<p className='dashboard--all-courses'>All courses</p>
<div className='dashboard'>
{displayCards}
<div className='dashboard--paginate'>
<ReactPaginate
previousLabel= {<img className='paginate--arrow-left' src ={left_arrow} alt ="prev"/>}
nextLabel = {<img className='paginate--arrow-right' src ={right_arrow} alt ="next"/>}
pageCount={pageCount}
onPageChange ={changePage}
containerClassName ={"paginationBtns"}
pageLinkClassName={"pageBtns"}
previousLinkClassName ={"prevBtn"}
nextLinkClassName ={"nextBtn"}
disabledClassName ={"disabledBtn"}
activeClassName ={"activeBtn"}/>
</div>
</div>
</div>
<div className='dashboard--right'>
hello
</div>
</div>
</div>
)
}
export default Dashboard
App.tsx
import React from 'react';
import Dashboard from './components/Dashboard';
import Wishlist from './components/Wishlist';
import Error from './components/Error';
import Cart from './components/Cart';
import Profile from './components/Profile';
import logo from './assets/logo.png'
import cart from './assets/cart.svg'
import profile from './assets/profile.svg'
import { BrowserRouter,Routes,Route, NavLink} from 'react-router-dom';
import './App.css';
function App() {
return (
<BrowserRouter>
<nav className='navbar'>
<li><NavLink to="/"><img className='navbar--logo' src={logo} alt ="Dashboard"/></NavLink></li>
<div className='navbar--links'>
<li><NavLink className="single" to="/">COURSES</NavLink></li>
<li><NavLink className="single" to ="/wishlist">MY WISHLIST</NavLink></li>
</div>
<div className='navbar--icons'>
<li><NavLink className='navbar--cart' to="/cart"><img src={cart} alt ="Cart"></img></NavLink></li>
<li><NavLink className='navbar--profile' to="/profile"><img src={profile} alt ="profile"></img></NavLink></li>
</div>
</nav>
<Routes>
<Route path='/' element={<Dashboard/>}/>
<Route path='wishlist' element={<Wishlist/>}/>
<Route path ='cart' element={<Cart/>}/>
<Route path ='profile' element ={<Profile/>}/>
<Route path='*' element={<Error/>}/>
</Routes>
</BrowserRouter>
);
}
export default App;
The other pages in App.tsx haven't been implemented yet, they only display basic components, and they they don't interfere with the working of dashboard.tsx. I don't know why the previously rendrered pagination buttons are vanishing. I have tried to inspect my code, and changed the values of the number of cards rendered per page. No matter the number, only the page is rendered. If someone has gone through this before and/or has a solution to this, that would be great.
I resolved the question! I hadn't destructured the 'selected' object while accessing it in my changePage function. Hope this is useful for anyone else who comes across this issue in the future
I have a website page that uses react-anime and react-typing-animation. My issue is to animate some elements displayed on it only once while the current session. So, if my site was opened on the main page, the animation would launch, and then, after switching a few pages and returning back to the main page, the animation wouldn't be executed again.
I've thought about sessionStorage, but I don't understand how to use it with these libraries.
Here's all the code:
index.js
import React from 'react'
import styles from './Index.module.css'
import Greeting from '../components/main/Greeting'
import Yelnya from '../components/main/Yelnya/Yelnya'
import BlueLakes from '../components/main/BlueLakes'
import Gallery from "../components/main/Gallery";
export default function Home() {
return (
<div className={styles.container}>
<Greeting />
<Yelnya />
<BlueLakes />
<Gallery />
</div>
)
}
Greeting.js
import React from 'react'
import styles from './Greeting.module.css'
import Tag from './Tag'
import Anime from "react-anime";
import Typing from "react-typing-animation"
export default function Greeting() {
return (
<div className={styles.root}>
<div className={styles.title}>
<Typing startDelay={50} speed={100}>
Explore Belarusian nature with us.
</Typing>
</div>
<div className={styles.hint}>
<Anime
opacity={[0,1]}
translateX={[-50,0]}
duration={3000}
delay={4200}
>
<p className={styles.hintTitle}>Go to:</p>
</Anime>
<Tag title="#Yelnya" link="/#yelnya" delay={4400}/>
<Tag title="#Blue lakes" link="/#blue-lakes" delay={4500}/>
<Tag title="#Galleries" link="/#galleries" delay={4600}/>
</div>
</div>
)
}
Tag.js
import React from 'react'
import styles from './Tag.module.css'
import Link from 'next/link'
import Anime from "react-anime";
export default function Tag({ title, link, delay }) {
return (
<Anime
opacity={[0,1]}
translateY={[50,0]}
duration={3000}
delay={delay}
>
<Link href={link}>
<div className={styles.tag}>
<p className={styles.text}>{title}</p>
</div>
</Link>
</Anime>
)
}
I made an example for using LocalStorage and handle animation with them
export default function App() {
const animated = !!localStorage.getItem("animated");
if (animated === false) {
localStorage.setItem("animated", true);
}
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
{!animated && (
<Anime
opacity={[0, 1]}
translateX={[-50, 0]}
duration={3000}
delay={500}
>
<p>Go to:</p>
</Anime>
)}
{animated && <p>Go to:</p>}
</div>
);
}
also you can test it here
I am trying to display the songs but for some reason my songs component is not even being executed. The console.log statement inside the Songs component is also not being logged to console. Also no errors of any sort are detected at all.
Here is my body component from which I am calling the Songs component
import './body.css'
import React from 'react'
import Header from './Header'
import { useStateValue } from './StateProvider';
import FavoriteIcon from '#material-ui/icons/Favorite';
import PlayCircleFilledIcon from '#material-ui/icons/PlayCircleFilled';
import MoreHorizIcon from '#material-ui/icons/MoreHoriz';
import Songs from './Songs.js'
function Body( {spotify}) {
const [{recently_played},dispatch] = useStateValue();
return (
<div className="body">
<Header spotify={spotify} />
<div className="body__info">
<img src={recently_played?.images[0].url} alt=""/>
<div className="body__infotext">
<strong>PLAYLIST</strong>
<h2>On Repeat</h2>
<p>{recently_played?.description}</p>
</div>
</div>
<div className="body__songs">
<div className="body__icons">
<PlayCircleFilledIcon className="body__shuffle"/>
<FavoriteIcon fontSize="large"/>
<MoreHorizIcon />
</div>
{recently_played?.tracks.items.map(item=>{
<Songs track={item.track} />
})}
</div>
</div>
)
}
export default Body
Here is the Songs component
import React from "react";
import './SongRow.css'
function Songs({ track }) {
console.log(track);
return (
<div className="songRow" >
<img className="songRow__album" src={track.album.images[0].url} alt="" />
<div className="songRow__info">
<h1>{track.name}</h1>
<p>
{track.artists.map((artist) => artist.name).join(", ")} -{" "}
{track.album.name}
</p>
</div>
</div>
);
}
export default Songs;
You are not returning anything inside the map
{recently_played?.tracks.items.map(item => {
return <Songs track={item.track} />;
})}
[or] use the shorthand version of arrow function
{recently_played?.tracks.items.map(item => <Songs track={item.track} />)}
I'm using map to view all posts using axios. And I just want show when I click a specific post to see more information. I'm using react parameters. But it's not working.
Here is my one component
import React, {Component} from 'react';
import Album from './album'
import {Link, BrowserRouter as Router, Route} from 'react-router-dom'
import axios from "axios"
class ViewDataAPI extends Component{
state = {
posts: []
}
componentDidMount(){
axios.get('https://jsonplaceholder.typicode.com/comments')
.then(response => {
this.setState({
posts: response.data
})
})
.catch(error => console.log('error'))
}
render(){
let { posts } = this.state
if(posts.length === 0){
return <h1>Loading...</h1>
}
else{
return(
<Router>
<div className="header">
<div className="container">
<div className="row">
<div className="col-lg-12 col-sm-12 col-xs-12">
<div className="text-center mb-20">
<h1>View Data From API</h1>
<p>using jsx-component, props, state, map in react </p>
</div>
</div>
</div>
<div className="row">
{
posts.map(post =>
{
return (
<Album
key={post.id}
name={post.name}
email = {post.email}
body = {post.body}
view = {post.id}
/>
)
}
)
}
</div>
{/* here is im using params, and to match by clicking specific id to show/view more information */}
<div className="row">
{posts && (
<Route path="/album/:albumId"
render = {({match}) => (
<ViewPosts {...posts.find(pv => pv.id === match.params.albumId)} />
)}
/>
)}
</div>
</div>
</div>
</Router>
)
}
}
}
export default ViewDataAPI;
// This component using for show details
const ViewPosts = ({posts}) =>{
return(
<div className="col-lg-6">
<div className="card border-dark mb-3">
<div className="card-body text-dark">
<div className="album">
<h3>{posts.name}</h3>
<h3>{posts.email}</h3>
<Link to="./">Back To Home</Link>
</div>
</div>
</div>
</div>
);
}
This is album component that has a link
import React, {Component} from 'react'
import {Link} from "react-router-dom"
class Album extends Component{
render(){
return(
<div className="col-lg-6">
<div className="card border-dark mb-3">
<div className="card-body text-dark">
<div className="album">
<h3>{this.props.name}</h3>
<p>{this.props.email}</p>
<p>{this.props.body}</p>
<Link to={`/album/${this.props.view}`}>View</Link>
</div>
</div>
</div>
</div>
);
}
}
export default Album;
https://react-pin.netlify.com/
Please follow the above link to what I'm trying to do. Please first go to one "View Data From API"
My github link https://github.com/sultan0/reactpin
The route param is a string. There is no implicit type conversion
with === Operator. Therefore you have to do it explicitly. Pls. see
Comparison operators for a further explanation.
The spread ... Operator is misplaced here.
The solution is:
<ViewPosts posts={posts.find(pv => pv.id === parseInt(match.params.albumId))} />
Update
You would like to use the Switch component from react router:
Switch is unique in that it renders a route exclusively. In contrast, every Route that matches the location renders inclusively.
Pls refer to react router documentation.
I created a pull request as an example. Hope it helps.