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} />} />
Related
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>
);
};
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
My app has two buttons, one that displays information and another that hides it. This works as intended, however, some of the images loaded in from the API don't have any data available, and when the button to display the info is pressed, it returns a []
How would I target those that load with an empty array, and add in a string. For example "no information for this breed is available?"
App.js
import './App.css';
import './Dog.js';
import './index.css';
import "./Grid.js";
import NestedGrid from './Grid.js';
import Album from './Grid.js';
import AppLayout from './Grid.js';
function DogApp() {
return (
<div className="dogApp">
<AppLayout />
</div>
);
}
export default DogApp;
Grid.js
import * as React from 'react';
import AppBar from '#mui/material/AppBar';
import Button from '#mui/material/Button';
import Card from '#mui/material/Card';
import CardActions from '#mui/material/CardActions';
import CardContent from '#mui/material/CardContent';
import CardMedia from '#mui/material/CardMedia';
import CssBaseline from '#mui/material/CssBaseline';
import Grid from '#mui/material/Grid';
import Stack from '#mui/material/Stack';
import Box from '#mui/material/Box';
import Toolbar from '#mui/material/Toolbar';
import Typography from '#mui/material/Typography';
import Container from '#mui/material/Container';
import Link from '#mui/material/Link';
import { createTheme, ThemeProvider } from '#mui/material/styles';
import FetchAPI from './FetchAPI';
const cards = [1, 2, 3, 4, 5, 6, 7, 8, 9];
const theme = createTheme();
export default function AppLayout() {
return (
<ThemeProvider theme={theme}>
<CssBaseline />
<AppBar position="relative">
</AppBar>
<main>
{/* Hero unit */}
<Box
sx={{
bgcolor: 'background.paper',
pt: 8,
pb: 6,
}}
>
<Container maxWidth="sm">
<Stack
sx={{ pt: 4 }}
direction="row"
spacing={2}
justifyContent="center"
>
</Stack>
</Container>
</Box>
<Container sx={{ py: 8 }} maxWidth="md">
{/* End hero unit */}
<Grid container spacing={4}>
{cards.map((card) => (
<Grid item key={card} xs={12} sm={6} md={4}>
<Card
sx={{ height: '100%', display: 'flex', flexDirection: 'column' }}
>
<FetchAPI />
<CardContent sx={{ flexGrow: 1 }}>
</CardContent>
</Card>
</Grid>
))}
</Grid>
</Container>
</main>
</ThemeProvider>
);
}
FetchAPI.js
import React, { useState, useEffect } from 'react'
const FetchAPI = () => {
const [show, setShow] = useState({});
const [data, setData] = useState([]);
const apiGet = () => {
const API_KEY = "";
fetch(`https://api.thedogapi.com/v1/images/search?limit=2&page=10&order=Desc?API_KEY=${API_KEY}`)
.then((response) => response.json())
.then((json) => {
console.log(json);
setData([...data, ...json]);
});
};
useEffect(() => { //call data when pagee refreshes/initially loads
apiGet();
}, []);
return (
<div>
{data.map((item, id) => (
<div>
<img alt="dog photos" className="dogImg" src={item.url}></img>
{show[id] === false ? <p>{JSON.stringify(item.breeds, null, '\t')}</p> : null}
<button onClick={() => setShow((prev) => ({ ...prev, [id]: false }))}>Learn more about this dog!</button>
<button onClick={() => setShow((prev) => ({ ...prev, [id]: true }))}>Hide information</button>
</div>
))}
</div>
)
}
export default FetchAPI;
You can compare the length of array like:
if(arr.length===0){
return "no information for this breed is available"
}
The above condition is just for understanding you can change the logic as well either you want to return or save in some state.
I have a page ("/paymentsucess"). In this page, I am using the react-countdown-circle-timer component (https://github.com/vydimitrov/react-countdown-circle-timer#props-for-both-reactreact-native). Upon reaching this page ("/paymentsuccess"), countdown beings. After countdown reaches zero, I want to redirect user back to home page ("/").
To achieve this, for the CountdownCircleTimer component, when onComplete, I set the state initialMount to false.
<CountdownCircleTimer
onComplete={() => {
setInitialMount(false);
return [true, 1500];
}}
isPlaying
duration={2}
colors={[
["#004777", 0.33],
["#F7B801", 0.33],
["#A30000", 0.33],
]}
>
{renderTime}
</CountdownCircleTimer>
Given that initialMount is changed, my useEffect (in the paymentsuccess component) will kick in and redirect users to "/". I am using history.push("/") here.
useEffect(() => {
if (initialMount !== true) {
console.log("On change in status,");
console.log(initialMount);
history.push("/");
}
}, [initialMount, history]);
I was able to redirect user back to "/" successfully. But upon reaching "/", they got redirected back to /paymentsuccess again. And then from /paymentsuccess it goes back to / and then the loops continue. Infinite loop.
Any idea what I am doing wrong here? :( I need to stop this loop and lands user back to / and stops there.
I am using Router from react-router-dom and createBrowserHistory from history.
Below is the full code for my paymentsuccess component
import React, { useEffect, useStatem} from "react";
import { useHistory } from "react-router-dom";
import { makeStyles } from "#material-ui/core/styles";
import Grid from "#material-ui/core/Grid";
import Paper from "#material-ui/core/Paper";
import { CountdownCircleTimer } from "react-countdown-circle-timer";
function PaymentSuccess() {
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
},
}));
const classes = useStyles();
const history = useHistory();
const [initialMount, setInitialMount] = useState(true);
useEffect(() => {
console.log("On component mount, status is");
console.log(initialMount);
}, []);
useEffect(() => {
return () => {
console.log("On component unmount, status is");
setInitialMount(true);
console.log(initialMount);
};
}, []);
useEffect(() => {
if (initialMount !== true) {
console.log("On change in status,");
console.log(initialMount);
history.push("/");
}
}, [initialMount, history]);
const renderTime = ({ remainingTime }) => {
if (remainingTime === 0) {
return <div className="timer">Starting...</div>;
}
return (
<div className="timer">
<div className="value">{remainingTime}</div>
</div>
);
};
return (
<div className={classes.root}>
<Grid container spacing={0}>
<Grid item xs={6} sm={6}>
<Paper
className="paymentSuccessLeftPaper"
variant="outlined"
square
></Paper>
</Grid>
<Grid item xs={6} sm={6}>
<Paper className="paymentSuccessRightPaper" variant="outlined" square>
<h1>Payment Success</h1>
<CountdownCircleTimer
onComplete={() => {
setInitialMount(false);
return [true, 1500];
}}
isPlaying
duration={2}
colors={[
["#004777", 0.33],
["#F7B801", 0.33],
["#A30000", 0.33],
]}
>
{renderTime}
</CountdownCircleTimer>
</Paper>
</Grid>
</Grid>
</div>
);
}
export default PaymentSuccess;
I have checked my "/" page and I don't think there is any logic there redirecting to "/paymentsuccess". The page ("/") code is as below.
import React from "react";
import { makeStyles } from "#material-ui/core/styles";
import Grid from "#material-ui/core/Grid";
import Paper from "#material-ui/core/Paper";
import Button from "#material-ui/core/Button";
import Link from "#material-ui/core/Link";
function LandingPage() {
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
},
paper: {
minHeight: "100%",
padding: theme.spacing(0),
textAlign: "center",
color: theme.palette.text.secondary,
},
}));
const classes = useStyles();
return (
<div className={classes.root}>
<Grid container spacing={0}>
<Grid item xs={4} sm={4}>
<Paper className={classes.paper} variant="outlined" square>
<h1>Photo Strips</h1>
<Button variant="contained" color="primary">
<Link href="/photo10">SELECT</Link>
</Button>
</Paper>
</Grid>
<Grid item xs={4} sm={4}>
<Paper className={classes.paper} variant="outlined" square>
<h1>Photo Strips and GIF</h1>
<Button variant="contained" color="primary">
<Link href="/photogif12">
SELECT
</Link>
</Button>
</Paper>
</Grid>
<Grid item xs={4} sm={4}>
<Paper className={classes.paper} variant="outlined" square>
<h1>Photo Strips and Boomerang</h1>
<Button variant="contained" color="primary">
<Link href="/photoboomerang12">
SELECT
</Link>
</Button>
</Paper>
</Grid>
</Grid>
</div>
);
}
export default LandingPage;
Thank you all in advance! Appreciate all the help and advise
UPDATE
Below is Router code
import React from "react";
import { Router, Switch } from "react-router-dom";
import LandingPage from "./components/LandingPage";
import Photo10 from "./components/Photo10";
import PhotoGIF12 from "./components/PhotoGIF12";
import PhotoBoomerang12 from "./components/PhotoBoomerang12";
import PaymentSuccess from "./components/PaymentSuccess";
import DynamicLayout from "./router/DynamicLayout";
import { history } from "./helpers/history";
const App = () => {
return (
<Router history={history}>
<div className="App">
<Switch>
<DynamicLayout
exact
path="/"
component={LandingPage}
layout="LANDING_NAV"
/>
<DynamicLayout
exact
path="/photo10"
component={Photo10}
layout="PHOTO10_PAGE"
/>
<DynamicLayout
exact
path="/photogif12"
component={PhotoGIF12}
layout="PHOTOGIF12_PAGE"
/>
<DynamicLayout
exact
path="/photoboomerang12"
component={PhotoBoomerang12}
layout="PHOTOBOOMERANG12_PAGE"
/>
<DynamicLayout
exact
path="/paymentsuccess"
component={PaymentSuccess}
layout="PAYMENTSUCCESS_PAGE"
/>
</Switch>
</div>
</Router>
);
};
export default App;
Below is the code for the DynamicLayout component
import React from "react";
const DynamicLayout = (props) => {
const { component: RoutedComponent, layout } = props;
const actualRouteComponent = <RoutedComponent {...props} />;
switch (layout) {
case "LANDING_NAV": {
return <>{actualRouteComponent}</>;
}
case "PHOTO10_PAGE": {
return <>{actualRouteComponent}</>;
}
case "PHOTOGIF12_PAGE": {
return <>{actualRouteComponent}</>;
}
case "PHOTOBOOMERANG12_PAGE": {
return <>{actualRouteComponent}</>;
}
case "PAYMENTSUCCESS_PAGE": {
return <>{actualRouteComponent}</>;
}
default: {
return (
<>
<h2>Default Nav</h2>
{actualRouteComponent}
</>
);
}
}
};
export default DynamicLayout;
This problem occurs when you changes value of variable in useEffect and that variable also added in useEffect dependency array, So when ever your useEffect change the value due to presence of that variable in dependency array, it again called the useEffect thus a infinite loop occurs
so just remove 'history' variable from your dependency array