I have React components :
Main.jsx
import { useState, useEffect } from "react";
import { Preloader } from "../Preloader";
import { Pokemons } from "../Pokemons";
import { LoadMore } from "../LoadMore";
function Main() {
const [pokemons, setPokemons] = useState([]);
const [loading, setLoading] = useState(true);
const [pokemonsPerPage] = useState("20");
const [pokemonOffset] = useState("0");
useEffect(function getPokemons() {
fetch(
`https://pokeapi.co/api/v2/pokemon?limit=${pokemonsPerPage}&offset=${pokemonOffset}`
)
.then((responce) => responce.json())
.then((data) => {
data.results && setPokemons(data.results);
setLoading(false);
});
}, []);
return (
<main className="container content">
{loading ? <Preloader /> : <Pokemons pokemons={pokemons} />}
<LoadMore />
</main>
);
}
export { Main };
LoadMore.jsx
import React from 'react'
function LoadMore() {
return (
<div className="button_container">
<a class="waves-effect waves-light btn-large" id="more">
More...
</a>
</div>
);
}
export { LoadMore };
I have created a button in the component. After clicking on it, the next 20 elements should be loaded. I created const [pokemonsPerPage] = useState("20"); and const [pokemonOffset] = useState("0"); in order to substitute these values into the request. The first is responsible for the number of objects on the page, the second is responsible for which element to start counting from. That is, now 20 elements are being output, starting from the very first one. (If you change const [pokemonOffset] = useState("0"); to 20, then the output will start from 21 elements). I'm sure that this is necessary for implementation, but I don't know what to do next
Help me complete this functionality
Here is what your Main.jsx should look like.
import { useState, useEffect } from "react";
import { Preloader } from "../Preloader";
import { Pokemons } from "../Pokemons";
import { LoadMore } from "../LoadMore";
function Main() {
const [pokemons, setPokemons] = useState([]);
const [loading, setLoading] = useState(true);
const [pokemonsPerPage] = useState(20);
const [page,setPage] = useState(1);
function getPokemons(pokemonOffset) {
fetch(
`https://pokeapi.co/api/v2/pokemon?limit=${pokemonsPerPage}&offset=${pokemonOffset}`
)
.then((responce) => responce.json())
.then((data) => {
data.results && setPokemons(data.results);
setLoading(false);
});
}
useEffect(() => {
const offset= page*pokemonsPerPage -pokemonsPerPage;
getPokemons(offset);
}, [page]);
return (
<main className="container content">
{loading ? <Preloader /> : <Pokemons pokemons={pokemons} />}
<LoadMore next={()=>setPage(p=>p+1)} />
</main>
);
}
export { Main };
while your Loadmore.jsx
import React from 'react'
function LoadMore(next) {
return (
<div className="button_container">
<a type="button" onclick={next} class="waves-effect waves-light btn-large" id="more">
More...
</a>
</div>
);
}
export { LoadMore };
Related
I Can't render my events. Its showing this error -
"Cannot update a component (App) while rendering a different component (EventList). To locate the bad setState() call inside EventList, follow the stack trace as described in https://reactjs.org/link/setstate-in-render"
Here is EventList Component code -
import { useEffect, useState } from "react";
import EventList from "../../event-list";
import EventForm from "../event-form";
const EventAction = ({
getEventsByClockID,
addEvent,
updateEvent,
clockID,
deleteEvent,
deleteEventsByClockID,
}) => {
const [isCreate, setIsCreate] = useState(false);
const [isToggle, setIsToggle] = useState(false);
const [eventState, setEventState] = useState(null)
const handleCreate = () => {
setIsCreate(!isCreate);
}
useEffect(() => {
setEventState(getEventsByClockID(clockID, true));
}, [isToggle])
const handleToggle = () => {
setIsToggle(!isToggle);
}
return (
<div>
<div>
<button onClick={handleCreate}>Create Event</button>
<button onClick={handleToggle}>Toggle Events</button>
</div>
{isCreate && (
<>
<h3>Create Event</h3>
<EventForm
clockID={clockID}
handleEvent={addEvent}
/>
</>
)}
{isToggle && (
<>
<h3>Events of this clock</h3>
<EventList
clockID={clockID}
eventState={eventState}
deleteEvent={deleteEvent}
updateEvent={updateEvent}
deleteEventsByClockID={deleteEventsByClockID}
/>
</>
)}
</div>
)
}
export default EventAction;
Here is my App Component Code -
import ClockList from "./components/clock-list";
import LocalClock from "./components/local-clock";
import useApp from "./hooks/useApp";
import { localClockInitState } from "./initialStates/clockInitState";
const App = () => {
const {
localClock,
clocks,
updateLocalClock,
createClock,
updateClock,
deleteClock,
getEventsByClockID,
addEvent,
deleteEvent,
updateEvent,
deleteEventsByClockID,
} = useApp(localClockInitState);
return (
<div>
<LocalClock
clock={localClock}
updateClock={updateLocalClock}
createClock={createClock}
/>
<ClockList
clocks={clocks}
localClock={localClock.date}
updateClock={updateClock}
deleteClock={deleteClock}
getEventsByClockID={getEventsByClockID}
addEvent={addEvent}
deleteEvent={deleteEvent}
updateEvent={updateEvent}
deleteEventsByClockID={deleteEventsByClockID}
/>
</div>
)
}
export default App;
and Here is my useApp hook -
import { useState } from "react";
import deepClone from "../utils/deepClone";
import generateID from "../utils/generateId";
import useEvents from "./useEvents";
const getID = generateID('clock');
const useApp = (initValue) => {
const [localClock, setLocalClock] = useState(deepClone(initValue));
const [clocks, setClocks] = useState([]);
const {
// events,
// getEvents,
getEventsByClockID,
addEvent,
deleteEvent,
deleteEventsByClockID,
updateEvent,
} = useEvents();
const updateLocalClock = (data) => {
setLocalClock({
...localClock,
...data,
})
}
const createClock = (clock) => {
clock.id = getID.next().value;
setClocks((prev) => ([
...prev, clock
]))
}
const updateClock = (updatedClock) => {
setClocks(clocks.map(clock => {
if(clock.id === updatedClock.id) return updatedClock;
return clock;
}));
}
const deleteClock = (id) => {
setClocks(clocks.filter(clock => clock.id !== id));
}
return {
localClock,
clocks,
updateLocalClock,
createClock,
updateClock,
deleteClock,
getEventsByClockID,
addEvent,
deleteEvent,
updateEvent,
deleteEventsByClockID,
}
}
export default useApp;
I want to show all events incorporated with each individual clock.
i've tried to make a fetch and take one element of the data base by id on Reactjs, backend with javascript(node + express + sequelize), but i had some problems and i couldn't at anytime. im searched on google but i dont know hot to apply the solutions on my code... here some examples of my trying:
import { useState } from "react";
import { useParams, Link } from "react-router-dom";
import "./detallesBarrio.css";
const BarriosDetails = () => {
const { id } = useParams();
const [barrio, setBarrio] = useState({});
const loadBarrioDetails = () => {
fetch("http://localhost:3001/api/barrios")
.then((x) => x.json())
.then((y) => y.data)
// .then((z) => console.log(z))
.then((allBarrio) => setBarrio(allBarrio));
};
let byid = barrio.filter(obj => {
return obj.id === id;
});
console.log(byid);
loadBarrioDetails();
return (
<main className="barrio-details">
{byid.map(obj => {
return (
<div key={obj.id}>
<div>
<h1>Detalles de {obj.nombre}</h1>
<img src={obj.foto} alt="imagen no disponible" />
<article>
<Link to="/barrios">Volver</Link>
</article>
</div>
</div>
);
})}
</main>
);
};
export default BarriosDetails;
also my tryings:
-no filter function (problem: map is not a function)
import { useState } from "react";
import { useParams, Link } from "react-router-dom";
import "./detallesBarrio.css";
const BarriosDetails = () => {
const { id } = useParams();
const [barrio, setBarrio] = useState({});
const loadBarrioDetails = () => {
fetch(`http://localhost:3001/api/barrios`)
.then((x) => x.json())
.then((y) => y.data)
// .then((z) => console.log(z))
.then((allBarrio) => setBarrio(allBarrio));
};
loadBarrioDetails();
return (
<main className="barrio-details">
{barrio.map((barri) => {
return (
<div key={barri.id}>
<div>
<h1>Detalles de {barri[id].nombre}</h1>
<img src={barri[id].foto} alt="imagen no disponible" />
<article>
<Link to="/barrios">Volver</Link>
</article>
</div>
</div>
);
})}
</main>
);
};
export default BarriosDetails;
-no maping (problem: the code dont recognise 'nombre'(database camp') on '{barrio[id].nombre}')
import { useState } from "react";
import { useParams, Link } from "react-router-dom";
import "./detallesBarrio.css";
const BarriosDetails = () => {
const { id } = useParams();
const [barrio, setBarrio] = useState({});
const loadBarrioDetails = () => {
fetch(`http://localhost:3001/api/barrios`)
.then((x) => x.json())
.then((y) => y.data)
.then((z) => console.log(z))
.then((allBarrio) => setBarrio(allBarrio));
};
loadBarrioDetails();
return (
<main className="barrio-details">
<div>
<h1>Detalles de {barrio[id].nombre}</h1>
<img src={barrio[id].foto} alt="imagen no disponible" />
<article>
<Link to="/barrios">Volver</Link>
</article>
</div>
</main>
);
};
export default BarriosDetails;
yes console.log give me the correct array
You are getting map is not a function because you're initiating the state as an object. is should be useState([]) instead of useState({})
based on your code you want to filter by id and id is unique so it's better to use array.find(obj => obj.id === id) than using array.filter().
in your first snippet let byid = barrio.filter(obj => { return obj.id === id; }); is executed before running the fetch and loading data.
try using useEffect for this kind of needs and loading data as a side effect after mounting the component and you should check the existance of an object or array before accessing it useEffect(() => loadBarrioDetails(), [])
Or since you just need one single object you can use like this:
import { useState } from "react";
import { useParams, Link } from "react-router-dom";
import "./detallesBarrio.css";
const BarriosDetails = () => {
const { id } = useParams();
const [barrio, setBarrio] = useState(null);
const loadBarrioDetails = () => {
fetch(`http://localhost:3001/api/barrios`)
.then((x) => x.json())
.then((y) => y.data)
.then((allBarrio) => {
const byId = allBarrio.find(obj => obj === id);
setBarrio(byId ?? null);
});
};
useEffect(() => loadBarrioDetails(), []);
if (!barrio) return <></> // anything to display that the data is loading or doesn't exist depends on you need.
return (
<main className="barrio-details">
<div>
<h1>Detalles de {barrio.nombre}</h1>
<img src={barrio.foto} alt="imagen no disponible" />
<article>
<Link to="/barrios">Volver</Link>
</article>
</div>
</main>
);
};
export default BarriosDetails;
I want the content to display when the tab is clicked. The issue that I'm having is that once the tab is clicked, all the tabs open... and likewise close when clicked again. I've been trying for hours to figure out how to fix this. I thought I had an answer by having a state that I could set the index to and then write a condition for the tab to open when the index of the state is the same but I noticed that after clicking on another tab, the other one closes. I would appreciate it so much if someone could help me open an individual tab when it's clicked and always stay open until clicked again, meaning, I could have multiple tabs open at once.
Here's a demo:
https://codesandbox.io/s/orrigenda-react-question-5oxg47
import React, { useEffect, useState } from 'react'
import axios from 'axios';
import LeaguesStyle from '../components/styles/LeaguesStyle.css';
const Leagues = () => {
const [teamz, setTeams] = useState([]);
const [loading, setLoading] = useState(false)
const [isOpen, setOpen] = useState(false);
const getTeams = async () => {
try {
const res = await axios.get('https://api-football-standings.azharimm.site/leagues');
setTeams(res.data.data)
setLoading(true);
console.log(res.data)
} catch (err) {
alert(err.message)
}
}
useEffect(() => {
getTeams();
}, []);
return (
<div className="leagues">
{loading &&
teamz.map(item => (
<div className='teamCard' key={item.id}>
<div onClick={() => setOpen(!isOpen)} className="teamDiv">
<img src={item.logos.dark} className='teamLogo' />
<h1>{item.name}</h1>
</div>
{isOpen && <div className='card-content-active'>{item.abbr}</div>}
</div>
))}
</div>
);
}
You need to track the individual truthy values per item.id. This can be easily done by using an object to keep track of all the previous states via the spread operator. Once an initial state is set per tab, then it's just a matter of toggling that individual state between true and false. You delineate between tabs by dynamically assigning the id to the truthy value ([id]: !isOpen[id]). Here is the code in totality:
import React, { useEffect, useState } from "react";
import axios from "axios";
import LeaguesStyle from "./LeaguesStyle.css";
const Leagues = () => {
const [teamz, setTeams] = useState([]);
const [loading, setLoading] = useState(false);
const [isOpen, setOpen] = useState({});
const getTeams = async () => {
try {
const res = await axios.get(
"https://api-football-standings.azharimm.site/leagues"
);
setTeams(res.data.data);
setLoading(true);
console.log(res.data);
} catch (err) {
alert(err.message);
}
};
useEffect(() => {
getTeams();
}, []);
const handleOpen = (id) => {
setOpen((prevTruthys) => ({ ...prevTruthys, [id]: !isOpen[id] }));
};
console.log(isOpen);
return (
<div className="leagues">
{loading &&
teamz.map((item) => (
<div className="teamCard" key={item.id}>
<div onClick={() => handleOpen(item.id)} className="teamDiv">
<img src={item.logos.dark} className="teamLogo" alt="logo" />
<h1>{item.name}</h1>
</div>
{isOpen[item.id] === true && (
<div className="card-content-active">{item.abbr}</div>
)}
</div>
))}
</div>
);
};
export default Leagues;
Here is the code sandbox: https://codesandbox.io/s/orrigenda-react-question-forked-42lbfo?file=/src/App.js
The solution is to store all clicked tabs in a list using the item ID, when the tab is open and you clicked again the ID is removed from the list
here is the code with the solution:
I created a function to update the state. setOpenById(tabId) and a function for checking if the tab is open isTabOpen(tabId)
the onClick now uses that function onClick={() => setOpenById(item.id)}
import React, { useEffect, useState } from "react";
import axios from "axios";
import LeaguesStyle from "./LeaguesStyle.css";
const Leagues = () => {
const [teamz, setTeams] = useState([]);
const [loading, setLoading] = useState(false);
const [openTab, setOpenTab] = useState([])
const getTeams = async () => {
try {
const res = await axios.get(
"https://api-football-standings.azharimm.site/leagues"
);
setTeams(res.data.data);
setLoading(true);
//console.log(res.data);
} catch (err) {
alert(err.message);
}
};
useEffect(() => {
getTeams();
}, []);
const setOpenById = (tabId) => {
if(!isTabOpen(tabId)){
setOpenTab([...openTab, tabId])
} else{
var array = [...openTab] // make a separate copy of the array
var index = array.indexOf(tabId)
if (index !== -1) {
array.splice(index, 1)
setOpenTab(array)
}
}
}
const isTabOpen = (tabId) => {
return openTab.indexOf(tabId) !== -1
}
return (
<div className="leagues">
{loading &&
teamz.map((item) => (
<div className="teamCard" key={item.id}>
<div onClick={() => setOpenById(item.id)} className="teamDiv">
<img src={item.logos.dark} className="teamLogo" alt="logo" />
<h1>{item.name}</h1>
</div>
{isTabOpen(item.id) && <div className="card-content-active">{item.abbr}</div>}
</div>
))}
</div>
);
};
export default Leagues;
I created a search component to get the cocktails by name, but I want to add another search option based on a checkbox(so the cocktail is alcoholically or not).
I have a context.js file:
import React, { useState, useContext, useEffect } from 'react'
import { useCallback } from 'react'
const url = 'https://www.thecocktaildb.com/api/json/v1/1/search.php?s='
const AppContext = React.createContext()
const AppProvider = ({ children }) => {
const [loading, setLoading] = useState(true)
const [searchTerm, setSearchTerm] = useState('a')
const [searchCheckbox, setSearchCheckbox] = useState(false)
const [cocktails, setCocktails] = useState([])
const fetchDrinks = useCallback(async () => {
setLoading(true)
setSearchCheckbox(false)
try {
const response = await fetch(`${url}${searchTerm}`)
const data = await response.json()
const {drinks} = data
if(!drinks) {
setCocktails([])
} else {
const searchedCocktails = drinks.map((drink) => {
const {idDrink, strDrink, strDrinkThumb, strInstructions,strAlcoholic, strIngredient1,strIngredient2} = drink
return {
id: idDrink,
name: strDrink,
image: strDrinkThumb,
isAlcoholic: strAlcoholic,
info: strInstructions,
ingredient1: strIngredient1,
ingredient2: strIngredient2
}
})
setCocktails(searchedCocktails)
}
setLoading(false)
} catch (error) {
console.log(error)
setLoading(false)
}
}, [searchTerm])
useEffect(() => {
fetchDrinks()
}, [searchTerm, fetchDrinks])
return <AppContext.Provider
value={{loading,
cocktails,
setSearchTerm,
setSearchCheckbox
}}>
{children}
</AppContext.Provider>
}
export const useGlobalContext = () => {
return useContext(AppContext)
}
export { AppContext, AppProvider }
The searchbar component is the following:
import React from 'react'
import { useGlobalContext } from '../helpers/context'
export default function SearchBar() {
const searchValue = React.useRef('')
const searchCheckbox = React.useRef(false)
const {setSearchTerm} = useGlobalContext()
const {setSearchCheckbox} = useGlobalContext()
const searchCocktail = () => {
setSearchTerm(searchValue.current.value)
setSearchCheckbox(searchCheckbox.current.checked)
}
const handleSubmit = (e) =>{
e.preventDefault()
}
//setup auto focus on input
React.useEffect(() => {
searchValue.current.focus()
searchCheckbox.current.focus()
}, [])
return (
<div className="container">
<div className="row">
<div className="col-12">
<div className="input-group">
<input className="form-control border-secondary py-2" type="search" ref={searchValue} onChange={searchCocktail}/>
<div className="input-group-append">
<button onClick={handleSubmit} className="btn btn-outline-secondary" type="button">
<i className="fa fa-search"></i>
</button>
</div>
</div>
</div>
<div className="col-12">
<div className="form-check">
<input className="form-check-input" type="checkbox" ref={searchCheckbox} onChange={searchCocktail} id="flexCheckDefault"/>
<label onClick={handleSubmit} className="form-check-label" htmlFor="flexCheckDefault">
Alcoholic
</label>
</div>
</div>
</div>
</div>
)
}
Can somebody can path me to a way to solve my problem? I haven't coded in React for some time and I think I m doing something hugely wrong with the useState hook on the checkbox
You need to create reference to state in parent element and pass it to child.
const [ alcoholicFilter, setAlcoholicFilter ] = useState(false) // false is default value
// here you can use `alcoholicFilter` variable and it will be updated
...
<Searchbar filter={setAlcoholicFilter}/>
After that in Searchbar component you can use this reference to update parent state
export default (props) => {
...
const handleSubmit = () => {
...
props.filter(input.checked) // you can set here to whatever you need
}
...
}
I'm building an ecommerce site. Right now, I'm pulling items from an API and displaying them ("Shop" component). I can click on an item to go to an item page ("Item" component) with more details/information on the clicked item. When I click the "Add to shopping cart" button (in the "Item" component), the clicked item is displayed in the shopping cart screen ("Cart" component).
In order to move items from one page to another, I'm using React Router (see "App" component), and using <Link /> to display specific parameters. I use the parameters to pass the item ID (and quantity) so I can call the API for that specific item.
This works for one item, but how do I adjust my code to allow more than one item to be displayed in the shopping cart?
Greatly appreciate any feedback.
App component:
import React, { useState } from 'react';
import './App.css';
import Nav from './Nav';
import Shop from './Components/Shop';
import Info from './Components/Info';
import Cart from './Components/Cart';
import Item from './Components/Item';
import {BrowserRouter as Router, Switch, Route} from 'react-router-dom';
function App() {
return (
<Router>
<div className="App">
<Nav />
<Route path="/" exact component={Shop} />
<Route path="/Info" component={Info} />
<Route path="/Cart/:id/:qty" component={Cart} />
<Route path="/Item/:item" component={Item} />
</div>
</Router>
)
}
export default App;
Shop component:
import React, { useState, useEffect } from 'react';
import './../App.css';
import * as ReactBootStrap from 'react-bootstrap';
import {Link} from 'react-router-dom';
function Shop() {
const [products, setProducts] = useState([]);
const [filterProducts, setFilteredProducts] = useState([]);
const [item, setItem] = useState('');
const [currentSort, setCurrentSort] = useState('');
const [loading, setLoading] = useState(false);
useEffect(async () => {
fetchItems();
}, [])
const fetchItems = async () => {
const data = await fetch('https://fakestoreapi.com/products');
const items = await data.json();
setProducts(items)
setLoading(true)
}
function priceUSD(change){
return change.toFixed(2)
}
useEffect(() => {
const filteredItems = products.filter((a) => {
if (item === '') {return a} else {return a.category === item}
});
setFilteredProducts(filteredItems);
}, [item, products])
useEffect(() => {
if (currentSort === '') {
return
}
const sortedItems = filterProducts.sort((a, b) => {
return currentSort === 'ASE' ? a.price - b.price : b.price - a.price
});
setFilteredProducts([...sortedItems]);
}, [currentSort])
return (
<div>
<div className="itemSort">
<p onClick={() => setItem("")}>All items</p>
<p onClick={() => setItem("men clothing")}>Men clothing</p>
<p onClick={() => setItem("women clothing")}>Women clothing</p>
<p onClick={() => setItem("jewelery")}>Jewelery</p>
<p onClick={() => setItem("electronics")}>Electronics</p>
</div>
<div className="itemSort">
<p>Order by price</p>
<p onClick={() => setCurrentSort('DESC')}>Highest</p>
<p onClick={() => setCurrentSort('ASE')}>Lowest</p>
</div>
<div className="gridContainer">
{loading ?
(filterProducts.map((a, index) => (
<Link to={`/Item/${a.id}`}>
<div key={index} className="productStyle">
<img src={a.image} className="productImage"></img>
<p>{a.title}</p>
<p>${priceUSD(a.price)}</p>
</div>
</Link>
))) : (<ReactBootStrap.Spinner className="spinner" animation="border" />)
}
</div>
</div>
)
}
export default Shop;
Item component:
import React, { useState, useEffect } from 'react';
import {Link} from 'react-router-dom';
import './../App.css';
import * as ReactBootStrap from 'react-bootstrap';
function Item(props) {
const [product, setProduct] = useState([]);
const [loading, setLoading] = useState(false);
const [quantity, setQuantity] = useState(1);
const [cost, setCost] = useState([]);
useEffect(async () => {
fetchItems();
}, [])
const itemId = props.match.params.item;
const fetchItems = async () => {
const data = await fetch('https://fakestoreapi.com/products/' + itemId);
const items = await data.json();
setProduct(items)
setLoading(true)
setCost(items.price)
}
function priceUSD(change){
return change.toFixed(2)
}
useEffect(() => {
const newCost = quantity * product.price;
setCost(priceUSD(newCost))
}, [quantity])
return (
<div className="App">
<h2>Item</h2>
<div className="gridContainer">
{loading ?
(<div key={itemId} className="productStyle">
<img src={product.image} className="productImage"></img>
<p>{product.title}</p>
<p>{product.description}}</p>
<p>${priceUSD(product.price)}</p>
<div className="quantity">
<button className="btn minus-btn" type="button"
onClick={quantity > 1 ? () => setQuantity(quantity - 1) : null}>-</button>
<input type="text" id="quantity" placeholder={quantity}/>
<button className="btn plus-btn" type="button"
onClick={() => setQuantity(quantity + 1)}>+</button>
</div>
<Link to={`/Cart/${itemId}/${quantity}`}>
<button type="button">
Add to shopping cart ${cost}
</button>
</Link>
</div>
): (<ReactBootStrap.Spinner className="spinner" animation="border" />)
}
</div>
</div>
);
}
export default Item;
Cart component:
import React, { useState, useEffect } from 'react';
import './../App.css';
import * as ReactBootStrap from 'react-bootstrap';
function Cart(props) {
const [cart, setCart] = useState([]);
const [quantity, setQuantity] = useState([]);
const [loading, setLoading] = useState(false);
useEffect(async () => {
fetchItems();
}, [])
const itemId = props.match.params.id;
const itemQuantity = props.match.params.qty;
const fetchItems = async () => {
const data = await fetch('https://fakestoreapi.com/products/' + itemId);
const items = await data.json();
setCart(items)
setQuantity(itemQuantity)
setLoading(true)
}
function price(qty){
const newPrice = qty * cart.price;
return newPrice
}
return (
<div>
{loading ? (
<div className="productStyle">
<img src={cart.image} className="productImage"></img>
<p>{cart.title}</p>
<div className="quantity">
<button className="btn minus-btn" type="button"
onClick={quantity > 1 ? () => setQuantity(quantity - 1) : null}>-</button>
<input type="text" id="quantity" placeholder={quantity}/>
<button className="btn plus-btn" type="button"
onClick={() => setQuantity(quantity + 1)}>+</button>
</div>
<p>${price(quantity)}</p>
</div>
) : (<ReactBootStrap.Spinner className="spinner" animation="border" />)}
</div>
);
}
export default Cart;
It is better if you persist the cart items in the localStorage.
In doing so, even when the user refreshes the tab, the app could load the data from the localStorage.
Example :-
Persisting data in the browser.
localStorage.setItem('my-app-cart-items', cartItems);
Retrieving data from the browser.
const cartItems = localStorage.setItem('my-app-cart-items');
Removing data from the browser
localStorage.removeItem('my-app-cart-items');