I'm pretty new to React, and I'm making an ecommerce website for practice. I have a cart component that dynamically renders cart items from an API, but I narrowed the problem 100% down to the front end. On the initial render, it works fine, everything that is in the database cart appears, however after I press the "Delete from Cart" button on a cart item, each cart item doubles.
CartCard.jsx
(/api/delete returns a json object of the cart AFTER deletion. deletion is handled in the api)
import React from "react";
import CartCardCSS from "./CartCard.module.css";
export default function CartCard(props) {
const passCart = props.passCart;
function deleteFromCart(e) {
e.preventDefault();
const item = {
id: props.id,
mainText: props.mainText,
price: props.price,
type: props.type
}
const user = {
username: props.username
}
const compoundEntity = {
theContent: item,
theUser: user
}
const requestOptions = {
method: "POST",
headers: {"Content-Type" : "application/json"},
body: JSON.stringify(compoundEntity)
}
fetch("/api/delete", requestOptions)
.then(response => response.json())
.then(response => {
passCart(response)
console.log(response)
})
}
return (
<div className={CartCardCSS.card}>
<img src={props.image} className={CartCardCSS.itempicture} alt="item picture"/>
<h3 className={CartCardCSS.subitem}>{props.mainText}</h3>
<h4 className={CartCardCSS.subitem}>{props.price}</h4>
<button onClick={deleteFromCart} className={`${CartCardCSS.subitem} ${CartCardCSS.button}`} type="button">Remove From Cart</button>
</div>
)
}
Cart.jsx:
import React, {useEffect, useState} from "react";
import CartCard from "./CartCard";
import CpuPicture from "./img/cpu.jpg";
import GpuPicture from "./img/gpu.jpg";
export default function Cart(props) {
const cart = props.cart;
const username = props.username;
const passCart = props.passCart;
const [arrCart, setArrCart] = useState(Object.values(cart))
const [cartComp, setCartComp] = useState()
useEffect(() => {
console.log(cart)
setArrCart(Object.values(cart))
for(let i = 0; i < arrCart.length; i++) {
setCartComp(arr => [arr, <CartCard key={i} id={i} passCart={passCart} username={username} mainText={arrCart[i].mainText} price={arrCart[i].price} type={arrCart[i].type} image={arrCart[i].type === "cpu" ? CpuPicture : GpuPicture}/>])
}
}, [cart])
return (
<div>
<h2 >Cart:</h2>
{cartComp}
</div>
)
}
Profile.jsx:
import React from "react";
import Cart from "./Cart";
import Navbar from "./Navbar";
import {useNavigate} from "react-router-dom";
export default function Profile(props) {
const username = props.username;
const isLoggedIn = props.isLoggedIn;
const cart = props.cart;
const passCart = props.passCart;
let navigate = useNavigate();
const routeChange = () => {
let path = "/login";
navigate(path);
}
if (isLoggedIn) {
return (
<div>
<Navbar />
<h1>{username}</h1>
<Cart passCart={passCart} username={username} cart={cart} />
</div>
)
} else {
routeChange();
}
}
App.jsx
import React, {useState} from "react";
import './App.css';
import Login from "./components/Login";
import Signup from "./components/Signup";
import Home from "./components/Home";
import Profile from "./components/Profile";
import Card from "./components/Card";
import GpuPicture from "./components/img/gpu.jpg";
import CpuPicture from "./components/img/cpu.jpg";
import {BrowserRouter, Routes, Route, Navigate} from "react-router-dom";
function App() {
const [username, setUsername] = useState('');
const [cart, setCart] = useState('');
const [isLoggedIn, setIsLoggedIn] = useState(false)
function passUsername(items) {
setUsername(items);
}
function passCart(items) {
setCart(items);
}
function passIsLoggedIn(items) {
setIsLoggedIn(items);
}
return (
<div className="App">
<BrowserRouter>
<Routes>
<Route path="/" element={<Navigate to="/login"/>} />
<Route path="/login" element={<Login passIsLoggedIn={passIsLoggedIn} passUsername={passUsername} passCart={passCart}/>}/>
<Route path="/signup" element={<Signup />}/>
<Route path="/home" element={<Home passCart={passCart} cart={cart} username={username} isLoggedIn={isLoggedIn} />} />
<Route path="/profile" element={<Profile passCart={passCart} cart={cart} username={username} isLoggedIn={isLoggedIn}/>} />
</Routes>
</BrowserRouter>
</div>
);
}
export default App;
Thanks for your help
As #deaponn mentioned, useState is asynchronous.
Your for loop in setCartComp is called n times. Alternatively what about using javascript's map function:
useEffect(() => {
console.log(cart);
// map transforms the array into an array of another type (in this case CartCard instances)
setCartComp(Object.values(cart).map((item, index) =>
<CartCard key={index} id={index}
passCart={passCart}
username={username}
mainText={item.mainText}
price={item.price}
type={item.type}
image={item.type === "cpu" ? CpuPicture : GpuPicture} />));
}, [cart]);
This for loop might be the issue:
useEffect(() => {
console.log(cart)
setArrCart(Object.values(cart))
for(let i = 0; i < arrCart.length; i++) {
setCartComp(arr => [arr, <CartCard key={i} id={i} passCart={passCart} username={username} mainText={arrCart[i].mainText} price={arrCart[i].price} type={arrCart[i].type} image={arrCart[i].type === "cpu" ? CpuPicture : GpuPicture}/>])
}
}, [cart])
Keep in mind that setState in react is asynchronous. What it means:
console.log(arrCart) // previous state
setArrCart(Object.values(cart))
console.log(arrCart) // still previous state
Try changing your for loop into that:
for(let i = 0; i < cart.length; i++) {
setCartComp(arr => [arr, <CartCard key={i} id={i} passCart={passCart} username={username} mainText={cart[i].mainText} price={cart[i].price} type={cart[i].type} image={cart[i].type === "cpu" ? CpuPicture : GpuPicture}/>])
}
Related
I'm building an e-commerce application and for some reason my buttons to update the cart aren't working. I'm using props and when I go to the console log it says that onUpdateCartQty is not a function. I know props are a bit tricky.
Can someone point out what I did wrong?
CartItem.jsx
import React from 'react';
import { Typography, Button, Card, CardActions, CardContent, CardMedia } from '#material-ui/core';
import useStyles from './styles';
const CartItem = ({ item, onUpdateCartQty, onRemoveFromCart }) => {
const classes = useStyles();
return (
//product.image.url?
<Card>
<CardMedia image={item.image.url} alt={item.name} className={classes.media} />
<CardContent className={classes.cardContent}>
<Typography variant="h4">{item.name}</Typography>
<Typography variant="h5">{item.line_total.formatted_with_symbol}</Typography>
</CardContent>
<CardActions className={classes.cardActions}>
<div className={classes.buttons}>
<Button type="button" size= "small" onClick={() => onUpdateCartQty(item.id, item.quantity - 1)}>-</Button>
<Typography>{item.quantity}</Typography>
<Button type="button" size= "small" onClick={() => onUpdateCartQty(item.id, item.quantity + 1)}>+</Button>
</div>
<Button variant="contained" type= "button" color="secondary" onClick={() => onRemoveFromCart(item.id) }>Remove</Button>
</CardActions >
</Card>
)
}
export default CartItem
App.js
import React, { useState, useEffect } from "react";
import { commerce } from './lib/commerce';
import { Products, Navbar, Cart } 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 handleEmptyCart = async () => {
const { cart } = await commerce.cart.empty();
setCart(cart);
}
const handleRemoveFromCart = async (productId) => {
const { cart } = await commerce.cart.remove(productId);
setCart(cart);
}
useEffect(() =>{
fetchProducts();
fetchCart();
}, []);
console.log(cart);
return (
<Router>
<div>
<Navbar totalItems={cart.total_items} />
<Routes>
<Route path= "/" element={<Products products = {products} onAddToCart=
{handleAddToCart}/>}/>
{/* <Products products={products} onAddToCart={handleAddToCart} /> */}
{/* </Route> */}
<Route path= "/cart" element= {<Cart cart={cart}/>}
handleUpdateCartQty ={handleUpdateCartQty}
handleRemoveFromCart ={handleRemoveFromCart}
handleEmptyCart ={handleEmptyCart}
/>
{/* <Cart cart={cart} /> */}
{/* </Route> */}
</Routes>
</div>
</Router>
);
};
export default App;
enter image description here
Currently, you are passing props to Route component not CartItem component.
<Route path= "/cart" element= {<Cart cart={cart}/>}
handleUpdateCartQty ={handleUpdateCartQty}
handleRemoveFromCart ={handleRemoveFromCart}
handleEmptyCart ={handleEmptyCart}
/>
Try to send as
<Route path= "/cart" element= {<Cart cart={cart}
handleUpdateCartQty ={handleUpdateCartQty}
handleRemoveFromCart ={handleRemoveFromCart}
handleEmptyCart ={handleEmptyCart}
/>} />
This question already has an answer here:
Why I receive blank page? React
(1 answer)
Closed 11 months ago.
I've used BrowserRouter here, and wrapped the within a tag.
But the problem is, the ShowTodoList page is not rendering.
Is this syntactically correct?
App.js file
import {BrowserRouter, Route, Routes} from 'react-router-dom';
import React, { lazy } from 'react';
import "./App.scss";
const ShowTodoList = lazy(() => import("./components/showTodoList"));
const CreateTodo = lazy(() => import("./components/createTodo"));
function App() {
return (
<div className="app-contents">
TODO - LIST
<BrowserRouter>
<Routes>
<Route path="/" component={ShowTodoList} />
</Routes>
</BrowserRouter>
</div>
);
}
export default App;
ShowTodoList.jsx
import { useState, useEffect } from "react";
import axios from "axios";
import { Link } from "react-router-dom";
import { UpdateTodo } from "./updateTodo";
function TodoCard({ data, handleEdit, handleDelete }) {
const { _id, title, description } = data;
return (
<li key={_id}>
<div className="title-description">
<h3>{title}</h3>
<p>{description}</p>
</div>
<div className="button-container">
<button className="button" name={_id} onClick={handleEdit}>
edit
</button>
<button className="button" name={_id} onClick={handleDelete}>
delete
</button>
</div>
</li>
);
}
export function ShowTodoList() {
const [todo, setTodo] = useState([]);
const [open, setOpen] = useState(false);
const [id, setId] = useState("");
const [update, setUpdate] = useState(false);
useEffect(
function () {
axios
.get("http://localhost:8000/api/todo")
.then((res) => {
console.log(res.data);
setTodo(res.data);
})
.catch((err) => {
console.log(err.message);
});
},
[update]
);
function handleEdit(e) {
setId(e.target.name);
setOpen(true);
}
function handleUpdate() {
console.log("update:", update, !update);
setUpdate(!update);
}
function handleDelete(e) {
axios.delete(`http://localhost:8000/api/todo/${e.target.name}`);
setTodo((data) => {
return data.filter((todo) => todo._id !== e.target.name);
});
}
function handleClose() {
setId("");
setOpen(false);
}
return (
<section className="container">
<Link to="/create-todo" className="button-new">
<button className="button">New</button>
</Link>
<section className="contents">
<h1>TODO</h1>
<ul className="list-container">
{todo.map((data) => (
<TodoCard
data={data}
handleEdit={handleEdit}
handleDelete={handleDelete}
/>
))}
</ul>
</section>
{open ? (
<section className="update-container">
<div className="update-contents">
<p onClick={handleClose} className="close">
×
</p>
<UpdateTodo
_id={id}
handleClose={handleClose}
handleUpdate={handleUpdate}
/>
</div>
</section>
) : (
""
)}
</section>
);
}
I'm getting a blank page as below:enter image description here
Could anybody please check the codes and point out where I'm going wrong?
If you are using react-router version 6, we don't have component props in this version, and you should use element instead of it.
import { BrowserRouter, Route, Routes } from "react-router-dom";
import React, { lazy, Suspense } from "react";
const ShowTodoList = lazy(() => import("./components/showTodoList"));
const CreateTodo = lazy(() => import("./components/createTodo"));
function App() {
return (
<div className="app-contents">
TODO - LIST
<Suspense fallback={<div>Loading...</div>}>
<BrowserRouter>
<Routes>
<Route path="/" element={<ShowTodoList />} />
</Routes>
</BrowserRouter>
</Suspense>
</div>
);
}
export default App;
I am trying to add the items to a cart page when a user clicks the add to cart button.
import React from "react";
import "bootstrap";
import { useParams } from "react-router-dom";
function ItemDetail(handleClick) {
const params = useParams();
let { productCode, vendor, value} = params;
let item = {productCode, vendor, value};
console.log(item);
return (
<>
<div>
<p>product id: {productCode}</p>
<p>price: {value}</p>
<p>vendor: {vendor}</p>
<button onClick={() => handleClick(item)}>Add to Cart</button>
</div>
</>
);
}
export default ItemDetail;
This is the cart page. Where I am to, render the item details from Item Details Page.
import React, { useState, useEffect } from "react";
const Cart = ({ cart, setCart, handleChange }) => {
const [price, setPrice] = useState(0);
const handleRemove = (id) => {
const arr = cart.filter((item) => item.id !== id);
setCart(arr);
handlePrice();
};
const handlePrice = () => {
let ans = 0;
cart.map((item) => (ans += item.amount * item.price));
setPrice(ans);
};
useEffect(() => {
handlePrice();
});
console.log(setCart);
return (
<article>
{cart.map((item) => (
<div className="cart_box" key={item.id}>
<div>
<button onClick={() => handleChange(item, 1)}>+</button>
<button>{item.amount}</button>
<button onClick={() => handleChange(item, -1)}>-</button>
</div>
<div>
<span>{item.price}</span>
<button onClick={() => handleRemove(item.id)}>Remove</button>
</div>
</div>
))}
<div className="total">
<span>Total Price of your Cart</span>
<span>R - {price}</span>
</div>
</article>
);
};
export default Cart;
This is my item description page. I have fetched the items using params, this is only way I found easier for me.
import React, { useState, useEffect } from "react";
import { Row, Col } from "react-bootstrap";
import StyledCard from "../components/Card";
const Discover = (props, params, handleClick) => {
const token = "not-the-actual-token";
const [result, setResult] = useState([]);
useEffect(() => {
fetch(
"https://api.flash-internal.flash-group.com/ecommerceManagement/1.0.0/api/product/",
{
method: "GET",
headers: { Authorization: `Bearer ${token}` },
}
)
.then((res) => res.json())
.then((json) => setResult(json));
}, []);
const cardStyle = {
listStyle: "none",
margin: 5,
paddingLeft: 0,
minWidth: 240,
};
return (
<>
<div className="latestdeals container my-5">
<h1>All Products</h1>
<Row className="hotcards">
<Col className="colcard">
{(result?.result || []).map((item) => (
<div key={item.productCode} style={cardStyle}>
<a href={`/itemDetail/${item.productCode}/${item.value}/${item.vendor}`}>
{" "}
<StyledCard
key={item.productCode}
name={item.vendor}
title={item.description}
price={item.value}
handleClick={handleClick}
item={item}
/>
</a>
</div>
))}
</Col>
</Row>
</div>
</>
);
};
export default Discover;
This is my App page
import "./index.scss";
import React, { useState } from "react";
import {
BrowserRouter as Router,
Route,
Routes,
useParams,
} from "react-router-dom";
import AllCategories from "./pages/all-catergories";
import Home from "./pages/home";
import Entertainment from "./pages/entertainment";
// import Cart from "./pages/_cart";
import Login from "./pages/login";
import Netflix from "./pages/netflix";
import Orders from "./pages/orders";
import SignUp from "./pages/sign-up";
// import Data2 from "./Data2";
import Products from "./pages/products";
// import Shop from "./components/Shop";
// import ProductDetail from "./pages/ProductDetail";
import Discover from "./pages/discover";
import ItemDetail from "./pages/itemDetail";
import Cart from "./pages/cart";
function App() {
const [show, setShow] = useState(true);
const [cart, setCart] = useState([]);
const handleClick = (item) => {
if (cart.indexOf(item) !== -1) return;
setCart([...cart, item]);
};
const handleChange = (item, d) => {
const ind = cart.indexOf(item);
const arr = cart;
arr[ind].amount += d;
if (arr[ind].amount === 0) arr[ind].amount = 1;
setCart([...arr]);
};
return (
<Router>
<Routes>
<Route path="/" element={<Home />} />
<Route path="all-categories" exact element={<AllCategories />} />
{/* <Route path="cart" exact element={<Cart />} /> */}
<Route path="entertainment" exact element={<Entertainment />} />
<Route path="login" exact element={<Login />} />
<Route path="discover" exact element={<Discover />} />
<Route path="netflix" exact element={<Netflix />} />
<Route path="orders" exact element={<Orders />} />
<Route path="sign-up" exact element={<SignUp />} />
<Route path="products" element={<Products />} />
<Route path="/itemDetail/:productCode/:value/:vendor" element={<ItemDetail />} />
<Route path="/itemDetail/" element={<ItemDetail handleClick={handleClick} />} />
<Route path="/Cart/" exact element={<Cart cart={cart} setCart={setCart} handleChange={handleChange}/>} />
</Routes>
</Router>
);
}
export default App;
Issues
You've issues declaring React components, several of them aren't using props correctly. function ItemDetail(handleClick) { ... } should be function ItemDetail({ handleClick }) { ... }, and const Discover = (props, params, handleClick) => { ... } should probably be something like const Discover = ({ params, handleClick, ...props }) => { ... }. React components receive a single props object argument.
handleChange in App is also mutating state.
Solution
App
Fix the state mutation and ensure props are passed correctly to routed components. Use an item GUID to search the cart instead of shallow reference equality when checking to add to the cart. When updating cart quantities it is necessary to shallow copy the cart array and cart items that are being updated. Use functional state updates whenever possible so it's ensured it's updating from the previous state and not any stale state value closed over in scope.
function App() {
const [show, setShow] = useState(true);
const [cart, setCart] = useState([]);
const handleClick = (item) => {
// Update cart item quantity if already in cart
if (cart.some((cartItem) => cartItem.productCode === item.productCode)) {
setCart((cart) =>
cart.map((cartItem) =>
cartItem.productCode === item.productCode
? {
...cartItem,
amount: cartItem.amount + 1
}
: cartItem
)
);
return;
}
// Add to cart
setCart((cart) => [
...cart,
{ ...item, amount: 1 } // <-- initial amount 1
]);
};
const handleChange = (productCode, d) => {
setCart((cart) =>
cart.flatMap((cartItem) =>
cartItem.productCode === productCode
? cartItem.amount + d < 1
? [] // <-- remove item if amount will be less than 1
: [
{
...cartItem,
amount: cartItem.amount + d
}
]
: [cartItem]
)
);
};
return (
<Router>
<Routes>
<Route path="/" element={<Home />} />
<Route path="all-categories" element={<AllCategories />} />
<Route path="entertainment" element={<Entertainment />} />
<Route path="login" element={<Login />} />
<Route path="discover" element={<Discover />} />
<Route path="netflix" element={<Netflix />} />
<Route path="orders" element={<Orders />} />
<Route path="sign-up" element={<SignUp />} />
<Route path="products" element={<Products />} />
<Route
path="/itemDetail/:productCode/:value/:vendor"
element={<ItemDetail handleClick={handleClick} />}
/>
<Route
path="/Cart/"
element={(
<Cart
cart={cart}
setCart={setCart}
handleChange={handleChange}
/>
)}
/>
</Routes>
</Router>
);
}
ItemDetail
Access/destructure the handleClick prop correctly. Pass the item's productCode to the callback.
function ItemDetail({ handleClick }) {
const { productCode, vendor, value} = useParams();
const item = { productCode, vendor, value };
return (
<div>
<p>product id: {productCode}</p>
<p>price: {value}</p>
<p>vendor: {vendor}</p>
<button onClick={() => handleClick(item)}>Add to Cart</button>
</div>
);
}
Discover
Correctly access/destructure the handleClick callback. Use the Link component instead of the raw anchor (<a />) tag. The anchor tag will reload the app which very likely isn't what you want to happen. Based on the code I suspect you don't actually need this handleClick since the ItemDetail component is passed it and adds to the cart
import { Link } from 'react-router-dom';
const cardStyle = {
listStyle: "none",
margin: 5,
paddingLeft: 0,
minWidth: 240,
};
const Discover = () => {
const token = "not-the-actual-token";
const [result, setResult] = useState([]);
useEffect(() => {
fetch(
"https://api.flash-internal.flash-group.com/ecommerceManagement/1.0.0/api/product/",
{
method: "GET",
headers: { Authorization: `Bearer ${token}` },
}
)
.then((res) => {
if (!res.ok) {
throw new Error('Network response was not OK');
}
return res.json();
})
.then((data) => setResult(data.result))
.catch(error => {
// handle any rejected Promises, errors, etc...
});
}, []);
return (
<div className="latestdeals container my-5">
<h1>All Products</h1>
<Row className="hotcards">
<Col className="colcard">
{result.map((item) => (
<div key={item.productCode} style={cardStyle}>
<Link to={`/itemDetail/${item.productCode}/${item.value}/${item.vendor}`}>
<StyledCard
name={item.vendor}
title={item.description}
price={item.value}
item={item}
/>
</Link>
</div>
))}
</Col>
</Row>
</div>
);
};
Cart
Don't store the cart total in state, it is easily derived from the cart state.
const Cart = ({ cart, setCart, handleChange }) => {
const handleRemove = (productCode) => {
setCart(cart => cart.filter(item => item.productCode !== productCode));
};
const price = cart.reduce((total, item) => total + item.amount * item.price, 0);
return (
<article>
{cart.map((item) => (
<div className="cart_box" key={item.id}>
<div>
<button onClick={() => handleChange(item.productCode, 1)}>+</button>
<button>{item.amount}</button>
<button onClick={() => handleChange(item.productCode, -1)}>-</button>
</div>
<div>
<span>{item.price}</span>
<button onClick={() => handleRemove(item.productCode)}>Remove</button>
</div>
</div>
))}
<div className="total">
<span>Total Price of your Cart</span>
<span>R - {price}</span>
</div>
</article>
);
};
I have this serch.js file. When I search and click on the li in the search result, I want to get redirected to <InnerDetail /> but the URL doesn't change or I don't get redirected to this page
but manualy if I type in the URL localhost/detiled/8 I am redirected to to <InnerDetail /> with id as 8
import React from "react";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import { faSearch } from "#fortawesome/free-solid-svg-icons";
import { useState, useEffect } from "react";
import axios from "axios";
import { Link } from "react-router-dom";
import { useHistory } from "react-router-dom";
const initialState = {
idaddProducts: "",
};
const Searchclients = () => {
const history = useHistory();
const [showResults, setShowResults] = React.useState(true);
const [poName, pnName] = React.useState(initialState);
const [showSerch, setShowSerch] = React.useState([]);
const [detail, setDetail] = useState(false);
const [inputValue, setInputValue] = React.useState("");
const [filteredSuggestions, setFilteredSuggestions] = React.useState([]);
const [selectedSuggestion, setSelectedSuggestion] = React.useState(0);
const [displaySuggestions, setDisplaySuggestions] = React.useState(false);
const suggestions = [];
showSerch.forEach(function (data) {
suggestions.push(data);
});
const onChange = (event) => {
const value = event.target.value;
setInputValue(value);
setShowResults(false);
const filteredSuggestions = suggestions.filter(
(suggestion) =>
suggestion.firstname
.toString()
.toLowerCase()
.includes(value.toLowerCase()) ||
suggestion.id.toString().toLowerCase().includes(value.toLowerCase())
);
setFilteredSuggestions(filteredSuggestions);
setDisplaySuggestions(true);
};
const onSelectSuggestion = (index) => {
setSelectedSuggestion(index);
setInputValue(filteredSuggestions[index]);
setFilteredSuggestions([]);
setDisplaySuggestions(false);
};
const SuggestionsList = (props) => {
// console.log(props);
const {
suggestions,
inputValue,
onSelectSuggestion,
displaySuggestions,
selectedSuggestion,
} = props;
if (inputValue && displaySuggestions) {
if (suggestions.length > 0) {
return (
<ul className="suggestions-list" style={styles.ulstyle}>
{suggestions.map((suggestion, index) => {
// console.log(suggestions);
const isSelected = selectedSuggestion === index;
const classname = `suggestion ${isSelected ? "selected" : ""}`;
return (
<Link to={`/detiled/${suggestion.id}`}> //this link dont work
<li
style={styles.listyle}
// onMouseOver={{ background: "yellow" }}
key={index}
className={classname}
>
{suggestion.firstname}
</li>
</Link>
);
})}
</ul>
);
} else {
return <div>No suggestions available...</div>;
}
}
return <></>;
};
useEffect(() => {
axios
.get("all-doctors-list/")
.then((res) => {
const data = res.data;
// pnName(data.data);
// var stringdata = data;
setShowSerch(data);
//console.log(stringdata);
});
// setShowSerch(data);
}, []);
return (
<>
<div className="note-container" style={styles.card}>
<div style={styles.inner}>
<p style={{ textAlign: "left" }}>Search Doctors</p>
<form className="search-form" style={{}}>
{showResults ? (
<FontAwesomeIcon
style={{ marginRight: "-23px" }}
icon={faSearch}
/>
) : null}
<input
onChange={onChange}
value={inputValue}
style={styles.input}
type="Search"
/>
<SuggestionsList
inputValue={inputValue}
selectedSuggestion={selectedSuggestion}
onSelectSuggestion={onSelectSuggestion}
displaySuggestions={displaySuggestions}
suggestions={filteredSuggestions}
/>
</form>
</div>
</div>
</>
);
};
export default Searchclients;
nav.js
import React from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import InnerDetail from "./client/doctor/components/innerto_detail.js";
class Navigator extends React.Component {
render() {
return (
<Router>
<div>
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/detiled/:id">
<InnerDetail />
</Route>
</div>
</Router>
);
}
}
function Home() {
return (
<div style={{ paddingTop: "20%", textAlign: "center" }}>
<h1>Home</h1>
</div>
);
}
export default Navigator;
You are missing closing tag of Switch:
import React from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import InnerDetail from "./client/doctor/components/innerto_detail.js";
class Navigator extends React.Component {
render() {
return (
<Router>
<div>
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/detiled/:id">
<InnerDetail />
</Route>
</Switch>
</div>
</Router>
);
}
}
function Home() {
return (
<div style={{ paddingTop: "20%", textAlign: "center" }}>
<h1>Home</h1>
</div>
);
}
export default Navigator;
Also its a tipo but you may want to say detailed, instead of detiled, but that does not affect.
i am trying create a transition screen from one page to the other
function MainPage(){
return (
<div>
{pagestate.navigating == "true" ? (
<FadeIn>
<div className="d-flex justify-content-center align-items-center">
<h1>signing you in ....</h1>
<Link to="/" color="black" >sign in</Link>
{pagestate.loading =="false" ? (
<Lottie options={defaultOptions} height={120} width={120} />
) : (
<Lottie options={defaultOptions2} height={220} width={120} />
)}
</div>
</FadeIn>
) : (
<div>
<h1>hello world</h1>
<Link to="/" color="black" >sign in</Link>
</div>
)}
The code works fine but I want it to navigate to /page2 when pagestate.loading = "false". I was able to achieve the page navigation with using
const history = useHistory()
then call navigation like
history.push('/page2')
I tried couple of method but could not get it work inside the transition logic.
How can I incorporate to the navigation into a new page after loading state has been changed to false in the transition logic above?
Encountered that a couple of days ago, i found a solution to it but it’s kinda weird,i’ve done it using redux, i’ve made a Link Component Called LinkWithAnimation,created a reducer as RouteReducer which will store current transition state, 2 states:
First one is For Transitioning In.
Second one is For Transitioning Out.
Wrapped my application with a div and passed the Transition that’s stored in redux, everytime LinkWithAnimation Is clicked This Is What Happens:
Dispatch An Action For Transitioning In
Wait(Delay) Till the Transition Has Finished(Depending On The Duration Of It)
Dispatch An Action for Transitioning Out.
And then push the new path using History API.
Note: Make Use Of Redux Thunk.
ActionTypes.js
export const ActionsType = {
...otherActions,
ANIMATION_IN: "animation-in",
ANIMATION_OUT: "animation-out",
};
ActionsCreator.js
import { ActionsType } from "./ActionsType.js";
import { history } from "../index.js";
export const ActionsCreator = {
...otherActionCreators,
userLogout: () => ({ type: ActionsType.LOGOUT }),
animateIn: () => ({ type: ActionsType.ANIMATION_IN }),
animateOut: () => ({ type: ActionsType.ANIMATION_OUT }),
pageTransition: (duration, path) => {
return async (dispatch) => {
const delay = async () => {
return new Promise((resolve) => setTimeout(resolve, duration));
};
dispatch(ActionsCreator.animateOut());
await delay();
dispatch(ActionsCreator.animateIn());
history.push(path);
};
},
};
index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { Router } from "react-router-dom";
import { createBrowserHistory } from "history";
export const history = createBrowserHistory();
ReactDOM.render(
<Router history={history}>
<React.StrictMode>
<App />
</React.StrictMode>
</Router>,
document.getElementById("root")
);
LinkWithAnimation.js
import React, { useRef, useEffect } from "react";
import { Link } from "react-router-dom";
import { ActionsCreator } from "../actions/ActionsCreator.js";
import { connect } from "react-redux";
const LinkWithAnimation = ({
className,
additionalFunction,
PageTransitioning,
to,
children,
style,
component,
ReactTo,
disabled,
}) => {
const LinkRef = useRef();
// This Effect To Handle Page Transition Once The User Is Signed In
useEffect(() => {
if (ReactTo === true) {
LinkRef.current.click();
}
}, [ReactTo]);
const componentProp =
component !== undefined
? {
component: component,
}
: {};
return (
<>
<Link
onClick={async () => {
if (disabled) return;
PageTransitioning(230, to);
if (additionalFunction !== undefined) {
additionalFunction();
}
}}
ref={LinkRef}
className={className}
style={{ ...style }}
{...componentProp}
>
{children}
</Link>
</>
);
};
const mapDispatchToProps = (dispatch) => ({
PageTransitioning: (duration, path) => {
dispatch(ActionsCreator.pageTransition(duration, path));
},
});
export default connect(null, mapDispatchToProps)(LinkWithAnimation);
Main.js
import React, { Fragment } from "react";
import { Switch, Route } from "react-router-dom";
import { connect } from "react-redux";
import Homepage from "./Homepage/Homepage.js";
import Signup from "./Signup/Signup.js";
import UserInterface from "./UserInterface/UserInterface.js";
import { SignIn } from "./SignIn/SignIn.js";
import { useRouteTransitionScroll } from "../hooks/useRouteTransitionScroll.js";
const Main = ({ keyframe }) => {
useRouteTransitionScroll({
from: "/signup",
to: "/home",
scroll_y: 650,
});
return (
<Switch component={Fragment}>
<div
style={{
animationName: keyframe,
animationDuration: "250ms",
animationTimingFunction: "linear",
}}
>
<Route path="/mainpage">
<UserInterface />
</Route>
<Route path="/home">
<Homepage />
</Route>
<Route path="/signin">
<SignIn />
</Route>
<Route path="/signup">
<Signup />
</Route>
</div>
</Switch>
);
};
const mapStateToProps = (state) => ({
keyframe: state.Route.animationName,
});
export default connect(mapStateToProps)(Main);