Created
June 3, 2025 06:15
-
-
Save sunmeat/34cf8d9f1260155e70c98e79d8e50577 to your computer and use it in GitHub Desktop.
tanstack query example react + localStorage
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {useState, useEffect} from 'react'; | |
import {QueryClient, QueryClientProvider, useQuery} from '@tanstack/react-query'; | |
import './App.css'; | |
const truncateText = (text, maxLength) => { | |
if (text.length > maxLength) { | |
return text.slice(0, maxLength) + '...'; | |
} | |
return text; | |
}; | |
// экземпляр QueryClient | |
const queryClient = new QueryClient(); | |
// компонента для получения и отображения продуктов | |
function ProductList({addToCart}) { | |
// API для получения продуктов | |
const fetchProducts = async () => { | |
const response = await fetch('https://fakestoreapi.com/products?limit=12'); | |
if (!response.ok) throw new Error('Ошибка загрузки продуктов'); | |
return response.json(); | |
}; | |
// useQuery для управления данными | |
const {data, error, isLoading} = useQuery({ | |
queryKey: ['products'], | |
queryFn: fetchProducts, | |
staleTime: 5 * 60 * 1000, // кэширование на 5 минут | |
}); | |
if (isLoading) return <div className="loading">Загрузка...</div>; | |
if (error) return <div className="error">Ошибка: {error.message}</div>; | |
return ( | |
<div className="product-list"> | |
<h2>Наши товары:</h2> | |
<div className="products"> | |
{data.map((product) => ( | |
<div key={product.id} className="product-card"> | |
<img src={product.image} alt={product.title} className="product-image"/> | |
<h3>{truncateText(product.title, 30)}</h3> | |
<p className="price">${product.price}</p> | |
<button onClick={() => addToCart(product)} className="add-to-cart"> | |
Добавить в корзину | |
</button> | |
</div> | |
))} | |
</div> | |
</div> | |
); | |
} | |
// компонента корзины | |
function Cart({cart, removeFromCart}) { | |
const total = cart.reduce((sum, item) => sum + item.price, 0).toFixed(2); | |
return ( | |
<div className="cart"> | |
<h2>Корзина</h2> | |
{cart.length === 0 ? ( | |
<p>Корзина пуста</p> | |
) : ( | |
<div> | |
{cart.map((item) => ( | |
<div key={item.id} className="cart-item"> | |
<span>{truncateText(item.title, 30)}</span> | |
<span>${item.price}</span> | |
<button onClick={() => removeFromCart(item.id)} className="remove-from-cart"> | |
Удалить | |
</button> | |
</div> | |
))} | |
<p className="total">Итого: ${total}</p> | |
</div> | |
)} | |
</div> | |
); | |
} | |
function App() { | |
// инициализация состояния корзины из localStorage | |
const [cart, setCart] = useState(() => { | |
const savedCart = localStorage.getItem('cart'); | |
return savedCart ? JSON.parse(savedCart) : []; | |
}); | |
// синхронизация корзины с localStorage при каждом изменении | |
useEffect(() => { | |
localStorage.setItem('cart', JSON.stringify(cart)); | |
}, [cart]); | |
const addToCart = (product) => { | |
setCart((prevCart) => [...prevCart, product]); | |
}; | |
const removeFromCart = (productId) => { | |
setCart((prevCart) => prevCart.filter((item) => item.id !== productId)); | |
}; | |
return ( | |
<QueryClientProvider client={queryClient}> | |
<div className="app"> | |
<h1>Интернет-магазин ReactExpress</h1> | |
<ProductList addToCart={addToCart}/> | |
<Cart cart={cart} removeFromCart={removeFromCart}/> | |
</div> | |
</QueryClientProvider> | |
); | |
} | |
export default App; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment