I have two page: Header.js and Post.js. These pages is joined on main page - Home.js. Post.js has button "Buy". This button creates variable with value 0 or 1. This value is saved on local storage with window.localStorage.setItem(). And I Want to take with value and give to Header.js. But when I do this value isn't updated avere time, when I click "buy"
How can I make this?
window.localStorage.setItem('countcart',count);
const sumCount = async () => {
if(count === 0){
setCount(Math.max(count+1,0));
} else{
setCount(Math.max(count-1,0));
}
};
<Button className={styles.buy} onClick={sumCount} variant="contained" endIcon={<ShoppingCartIcon fontSize="small"/>}><div className={styles.buytext}>Buy</div> </Button>
If you want localStorage to update every time count is changed, you should wrap it with a useEffect:
useEffect(() => {
window.localStorage.setItem('countcart',count);
}, [count])
But, this doesn't auto-update the count value in the other component; to do that with localStorage you'd need to use the https://developer.mozilla.org/en-US/docs/Web/API/Window/storage_event
But, a better way for the other component to access count would be to declare count as a state in the parent component and pass its state to the Header.js and Post.js components, e.g.:
// App.js
function App() {
const [count, setCount] = useCount(window.localStorage.getItem('count'));
useEffect(() => {
window.localStorage.setItem('countcart',count);
}, [count])
return (
<>
<Header count={count} setCount={setCount} />
<Post count={count} setCount={setCount} />
</>
)
}
import {Routes, Route} from 'react-router-dom';
import Container from '#mui/material/Container';
import { Header } from './components';
import { Home, FullPost, Registration, AddPost, Login, PostsByTag, Account } from './pages';
import { useDispatch, useSelector } from 'react-redux';
import React, { useState } from 'react';
import { fetchAuthMe, selectIsAuth } from './redux/slices/auth';
function App() {
const dispatch = useDispatch();
const [count, setCount] = useState(window.localStorage.getItem('countcart')? 0 :window.localStorage.getItem('countcart'));
const isAuth = useSelector(selectIsAuth);
React.useEffect(()=>{
dispatch(fetchAuthMe());
window.localStorage.setItem('countcart',count);
},[count])
return (
<>
<Header count={count} setCount={setCount}/>
<Container maxWidth="lg">
<Routes>
<Route path="/" element={<Home count={count} setCount={setCount}/>} />
<Route path="/posts/:id" element={<FullPost />} />
<Route path="/tags/:tag" element={<PostsByTag />} />
<Route path="/posts/:id/edit" element={<AddPost />} />
<Route path="/add-post" element={<AddPost />} />
<Route path="/login" element={<Login />} />
<Route path="/register" element={<Registration />} />
<Route path="/account/:id" element={<Account />} />
</Routes>
</Container>
</>
);
}
export default App;
import React from 'react';
import { Rating,IconButton, Button} from '#mui/material';
import clsx from 'clsx';
import {Link, useNavigate} from 'react-router-dom';
import DeleteIcon from '#mui/icons-material/Clear';
import EditIcon from '#mui/icons-material/Edit';
import EyeIcon from '#mui/icons-material/RemoveRedEyeOutlined';
import CommentIcon from '#mui/icons-material/ChatBubbleOutlineOutlined';
import ShoppingCartIcon from '#mui/icons-material/ShoppingCart';
import styles from './Post.module.scss';
// import { UserInfo } from '../UserInfo';
import { PostSkeleton } from './Skeleton';
import { useDispatch } from 'react-redux';
import { fetchRemovePost } from '../../redux/slices/posts';
export const Post = ({
id,
title,
createdAt,
imageUrl,
user,
viewsCount,
commentsCount,
tags,
children,
isFullPost,
isLoading,
isEditable,
count,
setCount,
}) => {
// const [count, setCount] = React.useState(0);
const dispatch = useDispatch();
const navigate = useNavigate();
if (isLoading) {
return <PostSkeleton />;
}
console.log(count);
window.localStorage.setItem('countcart',count);
const sumCount = async () => {
if(count === 0){
setCount(Math.max(count+1,0));
} else{
setCount(Math.max(count-1,0));
}
};
const onClickRemove = () => {
if(window.confirm('Do you sure want to remove post?')){
dispatch(fetchRemovePost(id));
navigate(0);
}
};
return (
<div className={clsx(styles.root, { [styles.rootFull]: isFullPost })}>
{isEditable && (
<div className={styles.editButtons}>
<Link to={`/posts/${id}/edit`}>
<IconButton color="primary">
<EditIcon />
</IconButton>
</Link>
<IconButton onClick={onClickRemove} color="secondary">
<DeleteIcon />
</IconButton>
</div>
)}
{imageUrl && (
<img
className={clsx(styles.image, { [styles.imageFull]: isFullPost })}
src={imageUrl}
alt={title}
/>
)}
<div className={styles.wrapper}>
<div className={styles.indention}>
<h2 className={clsx(styles.title, { [styles.titleFull]: isFullPost })}>
{isFullPost ? title : <Link to={`/posts/${id}`}>{title}</Link>}
</h2>
<div className={styles.ratingprice}>
<Rating
name="size-small"
value={2.5}
size="small"
precision={0.5}
readOnly
/>
<div className={styles.review}>12 отзывов</div>
</div>
<div className={styles.price}>1150 руб.</div>
{children && <div className={styles.content}>{children}</div>}
<div className={styles.postDetails}>
<ul className={styles.postDetails}>
<li>
<EyeIcon />
<span>{viewsCount}</span>
</li>
<li>
<CommentIcon />
<span>{commentsCount}</span>
</li>
</ul>
<Button className={styles.buy} onClick={sumCount} variant="contained" endIcon={<ShoppingCartIcon fontSize="small"/>}><div className={styles.buytext}>Купить</div> </Button>
</div>
</div>
</div>
</div>
);
};
Related
I want to build a car list app that will show a list of cars, and when I click on a car's details button, it will route it to another component/page that will show the details of cars.
I can get the key (vin for me) but I want to get the details of the car for each key(vin) on this page.It's like http://localhost:3000/cars/WAUZZZ4G6FN052847= key. So when a car's key will show up, all details will come due to their key number. Thank you.
index.html
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import { BrowserRouter, Routes, Route, Outlet, } from "react-router-dom";
import DummyComponent from "./components/DummyComponent";
import CarDetails from "./pages/CarDetails";
import { Home } from "#mui/icons-material";
import Cars from "./pages/Cars";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<BrowserRouter>
<Routes>
<Route path="/" element={<App />} />
<Route path="/cars" element={<Outlet />} >
<Route path="list" element={<Cars />} />
<Route path=":vin" element={<CarDetails />} />
</Route>
<Route path="Home" element={<Home />} />
<Route path="DummyComponent" element={<DummyComponent />} />
</Routes>
</BrowserRouter>
);
Cars.js
import axios from "axios";
import React, { useEffect, useState } from "react";
import List from '#mui/material/List';
import ListItem from '#mui/material/ListItem';
import ListItemButton from '#mui/material/ListItemButton';
import ListItemText from '#mui/material/ListItemText';
import { Link } from "react-router-dom";
const App = () => {
const [cars, setCars] = useState([])
const getCarData = async () => {
try {
const data = await axios.get("https://react-challenge-api.azurewebsites.net/vehicles")
setCars(data.data)
}
catch (e) {
console.log(e)
}
}
useEffect(() => {
getCarData()
}, [])
return (
<div className="App">
<List sx={{ width: '100%', maxWidth: 600, bgcolor: 'background.paper' }}>
{cars.map((car) => (
<ListItemButton key={car.vin}>
<ListItem
key={car.vin}
disableGutters
secondaryAction={
<ListItemButton >
<Link to={`/cars/${car.vin}`}>details</Link>
</ListItemButton>
}
>
<ListItemText key={car.vin} primary={car.model_variant} />
</ListItem>
</ListItemButton>
))
}
</List >
</div >
);
};
export default App;
CarDetails.js (I want to show each data in this component, I used params but I don't know how to get data due to params.
import { useParams } from "react-router-dom";
const CarDetails = () => {
let params = useParams();
return (
<>
<h1>car</h1>
<ul>
this is your {params.vin}
</ul>
</>
)
}
export default CarDetails;
I would suggest moving the car data fetching into a layout route and pass the cars state down in an Outlet context.
Example:
Cars - Handles fetching the car data and passes the cars state along to nested routes via the Outlet component's context.
const Cars = () => {
const [cars, setCars] = useState([]);
const getCarData = async () => {
try {
const data = await axios.get(
"https://react-challenge-api.azurewebsites.net/vehicles"
);
setCars(data.data);
} catch (e) {
console.log(e);
}
};
useEffect(() => {
getCarData();
}, []);
return <Outlet context={{ cars }} />;
};
CarList - Reads the cars state from the Outlet context and renders the list.
const CarList = () => {
const { cars } = useOutletContext();
return (
<List sx={{ width: "100%", maxWidth: 600, bgcolor: "background.paper" }}>
{cars.map((car) => (
<ListItemButton key={car.vin}>
<ListItem
key={car.vin}
disableGutters
secondaryAction={
<ListItemButton>
<Link to={`/cars/${car.vin}`}>details</Link>
</ListItemButton>
}
>
<ListItemText key={car.vin} primary={car.model_variant} />
</ListItem>
</ListItemButton>
))}
</List>
);
};
CarDetails - Takes the vin route path param and the cars array from the outlet context and searches for a matching car object.
const CarDetails = () => {
const { vin } = useParams();
const { cars } = useOutletContext();
const car = cars.find((car) => car.vin === vin);
if (!car) {
return "No car matches this VIN";
}
return (
<>
<h1>{car.model_variant}</h1>
<ul>
<li>Body: {car.body_type}</li>
<li>Doors: {car.doors}</li>
<li>Fuel: {car.fuel_type}</li>
<li>VIN: {car.vin}</li>
<li>Registration #: {car.regno}</li>
<li>Transmission: {car.transmission_type}</li>
</ul>
</>
);
};
Routes
<Routes>
<Route path="/" element={<App />} />
<Route path="/cars" element={<Cars />}> // <-- layout route renders outlet
<Route path="list" element={<CarList />} />
<Route path=":vin" element={<CarDetails />} />
</Route>
<Route path="Home" element={<Home />} />
<Route path="DummyComponent" element={<DummyComponent />} />
</Routes>
This is where i generate the token
import React, { useState, useEffect } from 'react';
import { Paper, Stepper, Step, StepLabel, Typography, CircularProgress, Divider, Button } from '#material-ui/core';
import { commerce } from '../../../lib/commerce';
import useStyles from './styles';
import AddressForm from '../AddressForm';
import PaymentForm from '../PaymentForm';
const steps = ['Shipping address', 'Payment details'];
const Checkout = ({ cart }) => {
const [activeStep, setActiveStep] = useState(0);
const [checkoutToken, setCheckoutToken] = useState(null);
const classes = useStyles();
useEffect(() => {
if (cart.id) {
const generateToken = async () => {
try {
const token = await commerce.checkout.generateToken(cart.id, { type: 'cart' });
setCheckoutToken(token)
} catch (error){
console.log(error);
}
};
generateToken();
}
}, [cart]);
const Confirmation = () => (
<div>
Confirmation
</div>
)
const Form = () => activeStep === 0
? <AddressForm checkoutToken={checkoutToken} />
: <PaymentForm />
return (
<>
<div className={classes.toolbar} />
<main className={classes.layout} >
<Paper className={classes.paper}>
<Typography variant='h4' align='center'>Checkout</Typography>
<Stepper activeStep={activeStep} className={classes.stepper}>
{steps.map((step) => (
<Step key={step}>
<StepLabel>{step}</StepLabel>
</Step>
))}
</Stepper>
{activeStep === steps.length ? <Confirmation /> : checkoutToken && <Form />}
</Paper>
</main>
</>
)
}
export default Checkout
Here is my App.js
import React, { useState, useEffect, Fragment } from 'react'
import { commerce } from './lib/commerce';
import { Products, Navbar, Cart, Checkout } from './components';
import { BrowserRouter as Router, Routes, Route} from 'react-router-dom';
const App = () => {
const [products, setProducts] = useState([]);
const [cart, setCart] = useState({});
const fetchProducts = async () => {
const { data } = await commerce.products.list();
setProducts(data);
}
const fetchCart = async () => {
setCart(await commerce.cart.retrieve())
}
const handleAddToCart = async ( productId, quantity) =>{
const { cart } = await commerce.cart.add(productId, quantity);
setCart(cart);
}
const handleUpdateCartQty = async (productId, quantity) => {
const { cart } = await commerce.cart.update(productId, { quantity });
setCart(cart);
}
const handleRemoveFromCart = async (productId) => {
const { cart } = await commerce.cart.remove(productId);
setCart(cart);
}
const handleEmptyCart = async () => {
const { cart } = await commerce.cart.empty();
setCart(cart);
}
useEffect(() => {
fetchProducts();
fetchCart();
}, []);
return (
<Router>
<div>
<Navbar totalItems={cart.total_items} />
<Routes>
<Route exact path='/' element={<Products products={products} onAddToCart={handleAddToCart} />} />
<Route exact path='/cart' element={<Cart cart={cart} handleUpdateCartQty={handleUpdateCartQty} handleAddToCart={handleAddToCart} handleRemoveFromCart={handleRemoveFromCart} handleEmptyCart={handleEmptyCart} />} />
<Route exact path='/checkout' element={ <Checkout cart={cart} />} />
</Routes>
</div>
</Router>
)
}
export default App;
And here is my cart.jsx incase their is anything relevant there
import React from 'react'
import { Container, Typography, Button, Grid} from '#material-ui/core';
import { Link } from 'react-router-dom';
import useStyles from './styles';
import CartItem from './CartItem/CartItem';
const Cart = ({ cart, handleUpdateCartQty, handleRemoveFromCart, handleEmptyCart }) => {
const classes = useStyles();
const EmptyCart = () => (
<Typography variant='subtitle1'>
You have no items in your shopping cart.
<Link to='/' className={classes.link}>Add Items!</Link>
</Typography>
);
const FilledCart = () => (
<>
<Grid container spacing={3}>
{ cart.line_items.map((item) => (
<Grid item xs={12} sm={4} key={item.id}>
<CartItem item={item} onUpdateCartQty={handleUpdateCartQty} onRemoveFromCart={handleRemoveFromCart} />
</Grid>
))}
</Grid>
<div className={classes.cardDetails}>
<Typography variant='h4'>
Subtotal: {cart.subtotal.formatted_with_symbol}
<div>
<Button className={classes.emptyButton} size='large' type='button' variant='contained' color='secondary' onClick={handleEmptyCart}>
Empty Cart
</Button>
<Button component={Link} to='/checkout' className={classes.checkoutButton} size='large' type='button' variant='contained' color='primary'>
Checkout
</Button>
</div>
</Typography>
</div>
</>
);
// Wait for cart to load items
if(!cart.line_items){
return '...loading';
}
return (
<Container>
<div className={classes.toolbar} />
<Typography className={classes.title} varaint='h3' gutterBottom >Your Shopping Cart</Typography>
{ !cart.line_items.length ? <EmptyCart /> : <FilledCart />}
</Container>
)
}
export default Cart
[error messages][1]
[1]: https://i.stack.imgur.com/vlard.png
Warning: Expected onSubmit listener to be a function, instead got a
value of string type. form
FormProvider#http://localhost:3000/static/js/bundle.js:76722:7
AddressForm#http://localhost:3000/static/js/bundle.js:1096:7 Form div
Paper#http://localhost:3000/static/js/bundle.js:12332:17
WithStyles#http://localhost:3000/static/js/bundle.js:19639:25 main
Checkout#http://localhost:3000/static/js/bundle.js:1332:7
Routes#http://localhost:3000/static/js/bundle.js:67209:7 div
Router#http://localhost:3000/static/js/bundle.js:67146:7
BrowserRouter#http://localhost:3000/static/js/bundle.js:65952:7
App#http://localhost:3000/static/js/bundle.js:347:82
Warning: A component is changing a controlled input to be
uncontrolled. This is likely caused by the value changing from a
defined to undefined, which should not happen. Decide between using a
controlled or uncontrolled input element for the lifetime of the
component. More info: https://reactjs.org/link/controlled-components
input SelectInput#http://localhost:3000/static/js/bundle.js:13482:19
div InputBase#http://localhost:3000/static/js/bundle.js:8257:25
WithStyles#http://localhost:3000/static/js/bundle.js:19639:25
Input#http://localhost:3000/static/js/bundle.js:9146:26
WithStyles#http://localhost:3000/static/js/bundle.js:19639:25
Select#http://localhost:3000/static/js/bundle.js:13182:26
WithStyles#http://localhost:3000/static/js/bundle.js:19639:25 div
Grid#http://localhost:3000/static/js/bundle.js:7352:29
WithStyles#http://localhost:3000/static/js/bundle.js:19639:25 div
Grid#http://localhost:3000/static/js/bundle.js:7352:29
WithStyles#http://localhost:3000/static/js/bundle.js:19639:25 form
FormProvider#http://localhost:3000/static/js/bundle.js:76722:7
AddressForm#http://localhost:3000/static/js/bundle.js:1096:7 Form div
Paper#http://localhost:3000/static/js/bundle.js:12332:17
WithStyles#http://localhost:3000/static/js/bundle.js:19639:25 main
Checkout#http://localhost:3000/static/js/bundle.js:1332:7
Routes#http://localhost:3000/static/js/bundle.js:67209:7
in my project, I'm trying, when I click a blog in many blogs. then only that blog will open in another route. and I set that route dynamically. and trying to load data using the find method. but that showing undefined. Please help me. below are my all codes.
this is my blogs page
import React, { useEffect, useState } from "react";
import { Card, Col, Row } from "react-bootstrap";
import { Swiper, SwiperSlide } from "swiper/react";
import "swiper/css";
import "swiper/css/pagination";
import { Pagination } from "swiper";
import "./Blog.css";
import ScrollToTop from "react-scroll-to-top";
import { HashLoader } from "react-spinners";
import { Link } from "react-router-dom";
const Blogs = () => {
const [blogs, setBlogs] = useState([])
useEffect(() => {
fetch('https://enigmatic-crag-58614.herokuapp.com/blogs')
.then(res => res.json())
.then(data=>setBlogs(data))
},[])
console.log(blogs);
return (
<div className="container my-5">
<ScrollToTop smooth color="#FE1A00" viewBox="0 0 250 250" />
<h1 className="text-danger">Blogs</h1>
{blogs.length === 0 && (
<h1 className="my-5 py-5">
<HashLoader color={'#FE1A00'} loading={true} size={150} />
</h1>
)}
<Row xs={1} md={3} className="g-4">
{
blogs.map(blog => <Col>
<Card className="shadow">
<Card.Img
variant="top"
src={blog.imageLink}
className="m-3"
/>
<Card.Body>
<h3 className="text-danger">{blog.heading}</h3>
<Card.Text>
{blog.text.slice(0, 200)}...
</Card.Text>
</Card.Body>
<strong className="mb-3">
<Link to={`/single-blog/${blog._id}`} className="see-more">
See More <i className="fas fa-arrow-circle-right"></i>{" "}
</Link>
</strong>
</Card>
</Col>)
}
</Row>
</div>
);
};
export default Blogs;
This is my single blog page
import React, { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import "./SingleBlog.css";
const SingleBlog = () => {
const { id } = useParams;
const [singleData, setSingleData] = useState([])
useEffect(() => {
fetch('https://enigmatic-crag-58614.herokuapp.com/blogs')
.then(res => res.json())
.then(data => setSingleData(data))
}, [])
console.log(singleData);
const matchedData = singleData.find((singleBlogPost) => singleBlogPost?._id == id)
console.log(matchedData);
return (
<div className="single-blog container w-75">
<div className="image-div mb-5 p-0">
<img
src="https://upload.wikimedia.org/wikipedia/commons/thumb/3/3f/Walking_tiger_female.jpg/220px-Walking_tiger_female.jpg"
alt=""
/>
</div>
<div>
<h1 className="text-danger">Tiger</h1>
<p className="text-start fs-5 fw-700">
The tiger (Panthera tigris) is the largest living cat species and a member of
the genus Panthera. It is most recognisable for its dark vertical stripes on
orange fur with a white underside. An apex predator, it primarily preys on
ungulates such as deer and wild boar. It is territorial and generally a solitary
but social predator, requiring large contiguous areas of habitat, which support
.
</p>
</div>
</div>
);
};
export default SingleBlog;
This is my app.js file
import "./App.css";
import Navigation from "./Components/Navigation/Navigation";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import HomePage from "./Components/HomePage/HomePage";
import AcdmClass from "./Components/AcademicClass/AcdmClass";
import ClassSubject from "./Components/ClassSubjects/ClassSubject";
import Lesson from "./Components/Lesson";
import Footer from "./Components/Footer/Footer";
import Contact from "./Components/Contact/Contact";
import Review from "./Components/Review/Review";
import Blogs from "./Components/Blog/Blogs";
import Signin from "./Components/Signin/Signin";
import Profile from "./Components/Profile/Profile";
import Skills from "./Components/Skills/Skills";
import AuthProvider from "./Contexts/AuthProvider";
import PrivateRoute from "./Components/PrivateRoute/PrivateRoute";
import SingleBlog from "./Components/SingleBlog/SingleBlog";
function App() {
return (
<div className="App">
<AuthProvider>
<BrowserRouter>
<Navigation></Navigation>
<Routes>
<Route path="/" element={<HomePage></HomePage>}></Route>
<Route path="home" element={<HomePage></HomePage>}></Route>
<Route path="blog" element={<Blogs></Blogs>}></Route>
<Route path="contact" element={<Contact></Contact>}></Route>
<Route path="skills" element={<Skills />}></Route>
<Route path="others" element={<Skills />}></Route>
<Route
path="/academic-class"
element={
<PrivateRoute>
<AcdmClass />
</PrivateRoute>
}
/>
<Route
path="/academicclass/:classnumber"
element={
<PrivateRoute>
<ClassSubject />
</PrivateRoute>
}
/>
<Route
path="/lesson"
element={
<PrivateRoute>
<Lesson />
</PrivateRoute>
}
/>
<Route
path="/profile"
element={
<PrivateRoute>
<Profile />
</PrivateRoute>
}
/>
<Route
path="/review"
element={
<PrivateRoute>
<Review />
</PrivateRoute>
}
/>
<Route
path="/single-blog/:id"
element={
<PrivateRoute>
<SingleBlog />
</PrivateRoute>
}
/>
<Route path="/sign-in" element={<Signin />} />
</Routes>
<Footer></Footer>
</BrowserRouter>
</AuthProvider>
</div>
);
}
export default App;
But showing this undefined please see this image
Try putting it in a useEffect like so
useEffect(()=>{
if(singleData){
console.log(singleData);
const matchedData = singleData.find((singleBlogPost) => singleBlogPost?._id == id)
console.log(matchedData);
}
},[singleData,id])
As initially singleData will be undefined and will be set after API call.
In react, The state of the component only get updated at the first time, So you need to tell the react to get the updated state.
In your singleBlog file -
const [singleData, setSingleData] = useState([])
useEffect(() => {
fetch('https://enigmatic-crag-58614.herokuapp.com/blogs')
.then(res => res.json())
.then(data => setSingleData(data))
}, [])
console.log(singleData);
const matchedData = singleData.find((singleBlogPost) => singleBlogPost?._id == id) //This line will never get the data until you ask the react to update the state (means to update the ```singleData``` array.
console.log(matchedData);
So you need to put the same method inside useEffect, and let the useEffect run whenever the state singleData get updated like this ->
useEffect(() => {
const matchedData = singleData.find((singleBlogPost) =>
singleBlogPost?._id == id)
console.log(matchedData);
}, [singleData, id]) //you need to add here all the dependencies, so that whenever these values will change you need to update your singleBlog page.
HERE IS YOUR FINAL CODE OF SINGLE BLOG PAGE ->
const SingleBlog = () => {
const { id } = useParams;
const [singleData, setSingleData] = useState([])
useEffect(() => {
fetch('https://enigmatic-crag-58614.herokuapp.com/blogs')
.then(res => res.json())
.then(data => setSingleData(data))
}, [])
useEffect(() => {
const matchedData = singleData.find((singleBlogPost) =>
singleBlogPost?._id == id)
console.log(matchedData);
}, [singleData, id])
return (
<div className="single-blog container w-75">
<div className="image-div mb-5 p-0">
<img
src="https://upload.wikimedia.org/wikipedia/commons/thumb/3/3f/Walking_tiger_female.jpg/220px-Walking_tiger_female.jpg"
alt=""
/>
</div>
<div>
<h1 className="text-danger">Tiger</h1>
<p className="text-start fs-5 fw-700">
The tiger (Panthera tigris) is the largest living cat species and a member of
the genus Panthera. It is most recognisable for its dark vertical stripes on
orange fur with a white underside. An apex predator, it primarily preys on
ungulates such as deer and wild boar. It is territorial and generally a solitary
but social predator, requiring large contiguous areas of habitat, which support
.
</p>
</div>
</div>
);
};
export default SingleBlog;
Pagination is not working in React Frontend. I am creating an Ecommerce Application and want to Paginate my products on my website. Here is the Code for Getting Product with Pagination.
const getProducts = asyncHandler(async (req, res, next) => {
const pageSize = 3;
const page = Number(req.query.pageNumber) || 1;
const keyword = req.query.keyword
? {
name: {
$regex: req.query.keyword,
$options: 'i',
},
}
: {};
const count = await Product.countDocuments({ ...keyword });
const products = await Product.find({ ...keyword })
.limit(pageSize)
.skip(pageSize * (page - 1))
.sort({ _id: -1 });
res.json({ products, page, pages: Math.ceil(count / pageSize) });
});
I am using Redux for state Management. Here is the code for the Reducer
// PRODUCT LIST
export const productListReducer = (state = { products: [] }, action) => {
switch (action.type) {
case PRODUCT_LIST_REQUEST:
return { loading: true, products: [] };
case PRODUCT_LIST_SUCCESS:
return {
loading: false,
pages: action.payload.pages,
page: action.payload.page,
products: action.payload.products,
};
case PRODUCT_LIST_FAIL:
return { loading: false, error: action.payload };
default:
return state;
}
};
And here is the Action code
// PRODUCT LIST
export const listProduct =
(keyword = ' ', pageNumber = ' ') =>
async (dispatch) => {
try {
dispatch({ type: PRODUCT_LIST_REQUEST });
const { data } = await axios.get(
`/api/products?keyword=${keyword}&pageNumber=${pageNumber}`
);
dispatch({ type: PRODUCT_LIST_SUCCESS, payload: data });
} catch (error) {
dispatch({
type: PRODUCT_LIST_FAIL,
payload:
error.response && error.response.data.error
? error.response.data.error
: error.message,
});
}
};
And this is the Component for pagination and few others
import React, { useEffect } from 'react';
import { Link } from 'react-router-dom';
import Rating from './Rating';
import Pagination from './pagination';
import { useDispatch, useSelector } from 'react-redux';
import { listProduct } from '../../Redux/Actions/ProductActions';
import Loading from '../LoadingError/Loading';
import Message from '../LoadingError/Error';
const ShopSection = (props) => {
const { keyword, pagenumber } = props;
const dispatch = useDispatch();
const productList = useSelector((state) => state.productList);
const { loading, error, products, page, pages } = productList;
useEffect(() => {
dispatch(listProduct(keyword, pagenumber));
}, [dispatch, keyword, pagenumber]);
return (
<>
<div className='container'>
<div className='section'>
<div className='row'>
<div className='col-lg-12 col-md-12 article'>
<div className='shopcontainer row'>
{loading ? (
<div className='mb-5'>
<Loading />
</div>
) : error ? (
<Message variant='alert-danger'>{error}</Message>
) : (
<>
{products.map((product) => (
<div
className='shop col-lg-4 col-md-6 col-sm-6'
key={product._id}
>
<div className='border-product'>
<Link to={`/products/${product._id}`}>
<div className='shopBack'>
<img src={product.image} alt={product.name} />
</div>
</Link>
<div className='shoptext'>
<p>
<Link to={`/products/${product._id}`}>
{product.name}
</Link>
</p>
<Rating
value={product.rating}
text={`${product.numReviews} reviews`}
/>
<h3>${product.price}</h3>
</div>
</div>
</div>
))}
</>
)}
{/* Pagination */}
<Pagination
pages={pages}
page={page}
keyword={keyword ? keyword : ''}
/>
</div>
</div>
</div>
</div>
</div>
</>
);
};
export default ShopSection;
And Pagination Component is here
import React from 'react';
import { Link } from 'react-router-dom';
const Pagination = (props) => {
const { page, pages, keyword = '' } = props;
return (
pages > 1 && (
<nav>
<ul className='pagination justify-content-center'>
{[...Array(pages).keys()].map((x) => (
<li
className={`page-item ${x + 1 === page ? 'active' : ''}`}
key={x + 1}
>
<Link
className='page-link'
to={
keyword
? `/search/${keyword}/page/${x + 1}`
: `/page/${x + 1}`
}
>
{x + 1}
</Link>
</li>
))}
</ul>
</nav>
)
);
};
export default Pagination;
And here is my App.js component
import React from 'react';
import './App.css';
import './responsive.css';
import 'react-toastify/dist/ReactToastify.css';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import HomeScreen from './screens/HomeScreen';
import SingleProduct from './screens/SingleProduct';
import Login from './screens/Login';
import Register from './screens/Register';
import CartScreen from './screens/CartScreen';
import ShippingScreen from './screens/ShippingScreen';
import ProfileScreen from './screens/ProfileScreen';
import PaymentScreen from './screens/PaymentScreen';
import PlaceOrderScreen from './screens/PlaceOrderScreen';
import OrderScreen from './screens/OrderScreen';
import NotFound from './screens/NotFound';
import PrivateRouter from './PrivateRoute';
const App = () => {
return (
<Router>
<Switch>
<Route path='/' component={HomeScreen} exact />
<Route path='/search/:keyword' component={HomeScreen} exact />
<Route path='/page/:pagenumber' component={HomeScreen} exact />
<Route
path='/search/:keyword/page/:pageNumber'
component={HomeScreen}
exact
/>
<Route path='/products/:id' component={SingleProduct} />
<Route path='/login' component={Login} />
<Route path='/register' component={Register} />
<PrivateRouter path='/profile' component={ProfileScreen} />
<Route path='/cart/:id?' component={CartScreen} />
<PrivateRouter path='/shipping' component={ShippingScreen} />
<PrivateRouter path='/payment' component={PaymentScreen} />
<PrivateRouter path='/placeorder' component={PlaceOrderScreen} />
<PrivateRouter path='/order/:id' component={OrderScreen} />
<Route path='*' component={NotFound} />
</Switch>
</Router>
);
};
export default App;
When i try to send request from postman the data is returning fine. I have already debug alot and couldn't able to resolve this bug. Help me to resolve this i will be grateful to you
You have to define pagenumber, because it is not defined.
const pagenumber = match.params.pagenumber;
Define it like this.
I hope it will work.
I want to access component according to the id of the product.
Here is my Code.
List.jsx
import { Switch, Route, Redirect, withRouter } from "react-router-dom";
import CategoryList from "./CategoryList.jsx";
import ProductList from "./ProductList.jsx";
import React from "react";
import axios from "axios";
const CategoryWithId = ({ match }) => {
console.log("Category", match.params.listId);
<ProductList listId={match.params.listId}></ProductList>;
};
function List() {
const [state, setState] = React.useState([]);
const getList = () => {
axios.get("https://api.growcify.com/dev/category/list").then((res) => {
console.log(res.data);
setState(res.data);
});
};
React.useEffect(() => {
getList();
}, []);
return (
<div className="App">
<Switch>
<Route path="/" component={() => <CategoryList state={state} />} />
<Route path="/product/:listId" component={CategoryWithId} />
<Redirect to="/" />
</Switch>
</div>
);
}
export default withRouter(List);
CategoryList.jsx
import React from "react";
import { Link } from "react-router-dom";
import Grid from "#material-ui/core/Grid";
import Paper from "#material-ui/core/Paper";
import { makeStyles } from "#material-ui/core/styles";
import { Typography } from "#material-ui/core";
const ShowCategory = (props) => {
const classes = useStyles();
const { list } = props;
return (
<Link to={`/product/${list._id}`}>
<Paper className={classes.paper} key={list._id}>
<p style={{ position: "relative", top: "40%" }}>{list.name}</p>
</Paper>
</Link>
);
};
function CategoryList(props) {
const { state } = props;
const classes = useStyles();
return (
<>
<div className={classes.header}>
<Typography variant="h3" style={{ padding: "10px" }}>
List of Categories
</Typography>
</div>
<div className={classes.container}>
<Grid container className={classes.root} spacing={2}>
<Grid item xs={12}>
<Grid container spacing={2}>
{state.map((list, index) => (
<ShowCategory list={list}></ShowCategory>
))}
</Grid>
</Grid>
</Grid>
</div>
</>
);
}
export default CategoryList;
I want that on clicking on Particular category, i should be redirect to /produce/listId.
In the url section, I can see the url with listId but I'm not getting redirected to the desired page related to that url.
Use exact keyword!
<Route exact path="/" component={() => <CategoryList state={state} />} />