我有纽扣(对于添加项目到localStorage)当我点击“添加到收藏夹”添加项目到localStorage,当我再次点击它从localStorage删除此项目,一切都很好。但当我刷新页面并点击按钮它只添加,我的意思是刷新点击,刷新点击,它只添加它必须删除,因为我已经添加了1次。当我点击两次而不刷新它删除1项,我想2-3次(多少次我添加了刷新)。如果给我假每次刷新,没有刷新(点击2次),那么它给我真的。我认为如果有什么问题。有人能帮助我吗?
import React, { useState } from 'react';
import { Button, Card } from 'react-bootstrap';
import { useThemeHook } from '../GlobalComponents/ThemeProvider';
import { useCart } from 'react-use-cart';
import { BsCartPlus } from 'react-icons/bs';
import { Link } from "@reach/router";
import { useInView } from 'react-intersection-observer';
import { MainContext, useContext } from '../context';
const ProductCard = (props) => {
// const [state,setState]=useState({
// favourites:[]
// });
const { favourites, setFavourites} = useContext(MainContext);
let { image, price, title, id } = props.data;
const [theme] = useThemeHook();
const { addItem } = useCart();
const { ref: headerAni, inView: headerAniVisible } = useInView();
const addToCart = () => {
addItem(props.data);
}
const handleFavourites = (likedItem) => {
let oldData = JSON.parse(localStorage.getItem('liked')) ?? []
if (favourites.includes(likedItem.id)) {
oldData = oldData.filter((m) => m.id !== likedItem.id)
console.log("if", oldData)
} else {
oldData.push(likedItem)
console.log("else", oldData)
}
localStorage.setItem("liked", JSON.stringify(oldData));
console.log(oldData);
handleFavouritesState();
};
const handleFavouritesState = () => {
let oldData = JSON.parse(localStorage.getItem("liked")) ?? []
let temp = oldData.map((likedItem) => likedItem.id);
setFavourites([...temp])
console.log("son", oldData)
};
return (
<>
<Card
style={{ width: '18rem', height: 'auto' }}
className={`${theme ? 'bg-light-black text-light' : 'bg-lihgt text-black'} text-center p-0 overflow-hidden shadow mx-auto mb-4`}
ref={headerAni}
>
<Link to={`/product-details/${id}`}>
<div style={{
background: 'white', height: '15rem', overflow: 'hidden', display: 'flex',
justifyContent: 'center', alignItems: 'center', marginBottom: 'inherit'
}}>
<div style={{ width: '9rem' }}>
<Card.Img variant="top" src={image} className="img-fluid" data-aos-easing="ease-out-cubic"
data-aos-duration="3000" data-aos={`${headerAniVisible ? "" : "zoom-out"}`} />
</div>
</div>
</Link>
<Card.Body>
<Card.Title style={{ textOverflow: 'ellipsis', overflow: 'hidden', whiteSpace: 'nowrap' }}>
{title}
</Card.Title>
<Card.Title>
$ <del><span className="">{price * 2}</span></del>
</Card.Title>
<Card.Title>
$ <span className="h3">{price}</span>
</Card.Title>
<Button
onClick={() => addToCart()}
className={`${theme ? 'bg-dark-primary text-black' : 'bg-light-primary'} d-flex align-item-center m-auto border-0`}
>
<BsCartPlus size="1.8rem" />
Add to cart
</Button>
<Button
onClick={() => handleFavourites(props.data)}
className={`${theme ? 'bg-dark-primary text-black' : 'bg-light-primary'} d-flex align-item-center m-auto border-0`}
>
<BsCartPlus size="1.8rem" />
Add to Favourites
</Button>
</Card.Body>
</Card>
</>
);
};
export default ProductCard;
我得到的数据从家庭组件与 prop ,如果它会帮助你
import { useRef } from 'react';
import React, { useEffect, useState } from 'react';
import { Container, Row, Col, InputGroup, FormControl } from 'react-bootstrap';
import { useThemeHook } from '../GlobalComponents/ThemeProvider';
import { BiSearch } from 'react-icons/bi';
import SearchFilter from 'react-filter-search';
import ProductCard from '../components/ProductCard';
import Carousel from 'react-bootstrap/Carousel';
import ScrollAnimation from 'react-animate-on-scroll';
import { useInView } from 'react-intersection-observer';
const Home = () => {
const [theme] = useThemeHook();
const [searchInput, setSearchInput] = useState('');
const [productData, setProductData] = useState([]);
const { ref: myRef, inView: myElementIsVisible } = useInView();
const { ref: rocketRef, inView: rocketIsVisible } = useInView();
const { ref: bannerOne, inView: bannerOneVisible } = useInView();
const { ref: headerAni, inView: headerAniVisible } = useInView();
async function getResponse() {
const res = await fetch('https://fakestoreapi.com/products')
.then(res => res.json());
setProductData(await res);
}
useEffect(() => {
getResponse();
}, []);
const [sortState, setSortState] = useState("none");
const sortMethods = {
none: { method: (a, b) => null },
ascending: { method: (a, b) => (a.price - b.price) },
descending: { method: (a, b) => (a.title > b.title ? 1 : -1) },
};
return (
<>
<Carousel fade className='padd-1' data-aos-easing="ease-out-cubic"
data-aos-duration="2000" data-aos={`${headerAniVisible ? "" : "fade-up"}`}>
<Carousel.Item ref={headerAni}>
<img
className="d-block w-100"
src="https://i.ibb.co/vwB9BV2/Untitled-design-33.png"
alt="First slide"
/>
<Carousel.Caption className='wid-300 pad-top' >
<h3>24/7 Texniki dəstək!</h3>
<p>
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. I
</p>
<a href='#' className='button'>More info</a>
</Carousel.Caption>
</Carousel.Item>
<Carousel.Item ref={headerAni}>
<img
className="d-block w-100"
src="https://i.ibb.co/PwrBm7q/Untitled-design-32.png"
alt="Second slide"
/>
<Carousel.Caption className='wid-300 pad-top' >
<h3>What is Lorem Ipsum?</h3>
<p>
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. I
</p>
<a href='#' className='button'>More info</a>
</Carousel.Caption>
</Carousel.Item>
<Carousel.Item ref={headerAni}>
<img
className="d-block w-100"
src="https://i.ibb.co/HYKM6z4/Untitled-design-34.png"
alt="Third slide"
/>
<Carousel.Caption className='wid-300 pad-top' >
<h3>What is Lorem Ipsum?</h3>
<p>
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. I
</p>
<a href='#' className='button'>More info</a>
</Carousel.Caption>
</Carousel.Item>
</Carousel>
<section className='home-wrapper-1 py-5' >
<div className='container-xxl padd' >
<div className='row' >
<div className='col-6'>
<div className='main-banner position-relative' ref={rocketRef}>
<img
src='https://i.ibb.co/PZtF0RM/main-banner-1.jpg'
className='img-fluid rounded-3'
alt='banner'
data-aos-easing="ease-out-cubic"
data-aos-duration="2000" data-aos={`${rocketIsVisible ? "" : "fade-right"}`}
/>
<div className='main-banner-content position-absolute' data-aos-easing="ease-out-cubic"
data-aos-duration="2000" data-aos={`${rocketIsVisible ? "" : "fade-right"}`}>
<h4>SUPERCHARGED FOR PODS</h4>
<h5>iPad S13+ Pro</h5>
<p>From $999.00 or $41.62/mo.</p>
<a href='#' className='button'>BUY NOW</a>
</div>
</div>
</div>
<div className='col-6'>
<div className='d-flex flex-wrap gap justify-content-between align-items-center'>
<div className='small-banner position-relative' ref={rocketRef}>
<img
src='https://i.ibb.co/HrZjrXC/catbanner-01.jpg'
className='img-fluid rounded-3'
alt='banner'
data-aos-easing="ease-out-cubic"
data-aos-duration="2000" data-aos={`${rocketIsVisible ? "" : "fade-down"}`}
/>
<div className='small-banner-content position-absolute' data-aos-easing="ease-out-cubic"
data-aos-duration="2000" data-aos={`${rocketIsVisible ? "" : "fade-down"}`}>
<h4>Best Sale</h4>
<h5>iPad S13+ Pro</h5>
<p>From $999.00 <br /> or $41.62/mo.</p>
</div>
</div>
<div className='small-banner position-relative' ref={rocketRef}>
<img
src='https://i.ibb.co/34Zk6Jv/catbanner-02.jpg'
className='img-fluid rounded-3'
alt='banner'
data-aos-easing="ease-out-cubic"
data-aos-duration="2000" data-aos={`${rocketIsVisible ? "" : "fade-down"}`}
/>
<div className='small-banner-content position-absolute' data-aos-easing="ease-out-cubic"
data-aos-duration="2000" data-aos={`${rocketIsVisible ? "" : "fade-down"}`}>
<h4>NEW ARRIVAL</h4>
<h5>Buy IPad Air</h5>
<p>From $999.00 <br /> or $41.62/mo.</p>
</div>
</div>
<div className='small-banner position-relative' ref={bannerOne}>
<img
src='https://i.ibb.co/5F9BZfw/catbanner-03.jpg'
className='img-fluid rounded-3'
alt='banner'
data-aos-easing="ease-out-cubic"
data-aos-duration="2000" data-aos={`${bannerOneVisible ? "" : "fade-up"}`}
/>
<div className='small-banner-content position-absolute' data-aos-easing="ease-out-cubic"
data-aos-duration="2000" data-aos={`${bannerOneVisible ? "" : "fade-up"}`}>
<h4>NEW ARRIVAL</h4>
<h5>Buy IPad Air</h5>
<p>From $999.00 <br /> or $41.62/mo.</p>
</div>
</div>
<div className='small-banner position-relative' ref={bannerOne}>
<img
src='https://i.ibb.co/pynHmdz/catbanner-04.jpg'
className='img-fluid rounded-3'
alt='banner'
data-aos-easing="ease-out-cubic"
data-aos-duration="2000" data-aos={`${bannerOneVisible ? "" : "fade-up"}`}
/>
<div className='small-banner-content position-absolute' data-aos-easing="ease-out-cubic"
data-aos-duration="2000" data-aos={`${bannerOneVisible ? "" : "fade-up"}`}>
<h4>NEW ARRIVAL</h4>
<h5>Buy IPad Air</h5>
<p>From $999.00 <br /> or $41.62/mo.</p>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<Container className="py-4">
<Row className="justify-content-center">
<Col xs={10} md={7} lg={6} xl={4} className="mb-3 mx-auto text-center">
<h1 className={theme ? 'text-light my-5' : 'text-black my-5'}>Search products</h1>
<InputGroup className="mb-3">
<InputGroup.Text className={theme ? 'bg-black text-dark-primary' : 'bg-light text-light-primary'}>
<BiSearch size="2rem" />
</InputGroup.Text>
<FormControl
placeholder="Search"
value={searchInput}
onChange={(e) => setSearchInput(e.target.value)}
className={theme ? 'bg-light-black text-light' : 'bg-light text-black'}
/>
</InputGroup>
</Col>
<div style={{ width: '100%', display: 'flex', justifyContent: 'center' }} className='mb-3'>
<select style={{ width: '100px' }} defaultValue={'none'} onChange={(e) => setSortState(e.target.value)}>
<option value="none">None</option>
<option value="ascending">Price</option>
<option value="descending">A-Z</option>
</select>
</div>
<SearchFilter
value={searchInput}
data={productData}
renderResults={results => (
<Row className="justify-content-center">
{results?.sort(sortMethods[sortState].method).map((item, i) => (
<ProductCard data={item} key={i} />
))}
</Row>
)}
/>
</Row>
</Container>
</>
);
};
export default Home;
1条答案
按热度按时间u5rb5r591#
看来问题出在“handleFavourites”的逻辑上
};
检查从localStorage检索的oldData是否包含likedItem的id
}