英文:
Counter using Usestate
问题
我有一个对象,它有一个键值为quantity的属性。我想能够使用增加器和减少器来更新quantity的值。我能够做到这一点,但由于需要使用useState的currentState,我无法将我的网站上线。目前,我已经尝试了很多种方法来整合currentState,但从未成功过!我需要更改singleProducts.quantity,以便它也可以在子组件中使用!
这是我目前的代码:
import React, { useState, useContext } from 'react';
import { Link, useParams } from 'react-router-dom';
import GetSingleProduct from '../Hooks/getSingleProduct';
import { AppContext } from '../Context/Context';
import '../Assets/Styles/Product.css';
function Product() {
const { id } = useParams();
const { singleProduct, isLoading, error } = GetSingleProduct(`https://makeup-api.herokuapp.com/api/v1/products/${id}.json`);
const [clickedColour, setClickedColour] = useState([]);
const Cartstate = useContext(AppContext);
const dispatch = Cartstate.dispatch;
const handleColour = (index) => {
setClickedColour((prevstate) => ({
...prevstate,
[index]: !prevstate[index],
}));
};
const [newQuantity, setNewQuantity] = useState({ ...singleProduct });
const handleIncrement = () => {
const updatedNum = { ...singleProduct, quantity: singleProduct.quantity + 1 };
console.log(updatedNum);
console.log(newQuantity);
setNewQuantity(updatedNum);
};
const handleDecrement = () => {
setNewQuantity({ ...singleProduct, quantity: newQuantity.quantity - 1 });
};
return (
<>
<div className="routeTaken">
<ol>
<li><Link to="/">Home</Link></li>
<li><Link to="/shop">Shop</Link></li>
<li>Current page</li>
</ol>
</div>
<div className="productInfo">
{error && <div>{error}</div>}
{isLoading ? (
<div>Loading...</div>
) : (
<div id={singleProduct.id}>
<img src={singleProduct.api_featured_image} alt={singleProduct.product_type} />
<p>{singleProduct?.product_type ? singleProduct.product_type.charAt(0).toUpperCase() + singleProduct.product_type.slice(1).toLowerCase().split('_').join(' ') : singleProduct.product_type}</p>
<h1>{singleProduct?.brand ? singleProduct.brand.charAt(0).toUpperCase() + singleProduct.brand.slice(1).toLowerCase() : singleProduct.brand} {singleProduct?.name ? singleProduct.name.charAt(0).toUpperCase() + singleProduct.name.slice(1).toLowerCase() : singleProduct.name}</h1>
<h2>£{singleProduct.price === '0.0' || singleProduct.price === null ? '8.50' : Number(singleProduct.price).toFixed(2)}</h2>
<h3>{singleProduct.description}</h3>
<div className="colourList grid grid-cols-4">
{singleProduct.product_colors?.map((colour, index) => (
<button onClick={() => handleColour(index)} className="colourItem" key={index} style={{ backgroundColor: colour.hex_value }}>
{colour.hex_value}
{clickedColour[index] ? (
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="w-6 h-6">
<path strokeLinecap="round" strokeLinejoin="round" d="M4.5 12.75l6 6 9-13.5" />
</svg>
) : (null)}
</button>
))}
</div>
<div className="counter">
<button onClick={handleIncrement} disabled={singleProduct.quantity >= 10}>
+
</button>
<p>{newQuantity.quantity}</p>
<button onClick={handleDecrement} disabled={newQuantity.quantity <= 0}>
-
</button>
</div>
<button onClick={() => dispatch({ type: 'ADD', payload: singleProduct })}>Add to basket</button>
</div>
)}
</div>
</>
);
}
export default Product;
当我在每次增加按钮后使用console.log(updatedNum)
时,它显示增加了,但当我对newQuantity
这样做时却不起作用!
我已经尝试过:
const updatedNum = { ...newQuantity, quantity: newQuantity.quantity + 1 };
但它总是返回NaN。
我还在我的JSX中放置了{newQuantity.quantity}
和{singleProduct.quantity}
来查看。似乎newQuantity
有延迟,且比singleProduct
晚一步。
希望这能帮助解决问题!
英文:
I have an object which has a key value of quantity. I want to be able to update the quantity value using an incrementor and decrementor. I am able to do this but unable to make my site live as I need to use the currentState of useState. Currently I've tried many ways to incorporate currentState but it never works! I need the singleProducts.quantity to be changed so that it can be used on a child component also!
Here is what I have so far:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
import React from 'react'
import { Link, useParams } from 'react-router-dom'
import { useState, useContext } from 'react'
import GetSingleProduct from '../Hooks/getSingleProduct'
import { AppContext } from '../Context/Context'
import '../Assets/Styles/Product.css'
function Product() {
// able to use useParams to direct to the page with the id of the product that has been clicked
const { id } = useParams()
const { singleProduct, isLoading, error } = GetSingleProduct(`https://makeup-api.herokuapp.com/api/v1/products/${id}.json`)
const [clickedColour, setClickedColour] = useState([])
// useContext for the add to cart
const Cartstate = useContext(AppContext)
const dispatch = Cartstate.dispatch;
const handleColour = (index) => {
setClickedColour(prevstate =>
({
...prevstate, [index] // copies prev state
: !prevstate[index]
}))
console.log(setClickedColour)
}
const [newQuantity, setNewQuantity] = useState({...singleProduct})
const handleIncrement = () => {
const updatedNum = { ...singleProduct, quantity: singleProduct.quantity ++ }
console.log(updatedNum)
console.log(newQuantity)
setNewQuantity(updatedNum)
}
const handleDecrement = () => {
setNewQuantity({ ...singleProduct, quantity:newQuantity.quantity-- })
}
return (
<>
<div className='routeTaken'>
<ol>
<li><Link to='/'>Home</Link></li>
<li><Link to='/shop'>Shop</Link></li>
<li>Current page</li>
</ol>
</div>
<div className='productInfo'>
{error && <div>{error}</div>}
{isLoading ?
(<div>Loading...</div>) :
<div id={singleProduct.id}>
<img src={singleProduct.api_featured_image} alt={singleProduct.product_type}></img>
<p>{singleProduct?.product_type ? singleProduct.product_type.charAt(0).toUpperCase() + singleProduct.product_type.slice(1).toLowerCase().split('_').join(' ') : singleProduct.product_type}</p>
<h1>{singleProduct?.brand ? singleProduct.brand.charAt(0).toUpperCase() + singleProduct.brand.slice(1).toLowerCase() : singleProduct.brand} {singleProduct?.name ? singleProduct.name.charAt(0).toUpperCase() + singleProduct.name.slice(1).toLowerCase() : singleProduct.name}</h1>
<h2> £{singleProduct.price==='0.0'||singleProduct.price === null ? '8.50': Number(singleProduct.price).toFixed(2)}</h2>
<h3>{singleProduct.description}</h3>
<div className="colourList grid grid-cols-4">
{singleProduct.product_colors?.map((colour, index) => {
return (
<button onClick={() => handleColour(index)} className='colourItem' key={index} style={{ backgroundColor: colour.hex_value }}>
{colour.hex_value}
{clickedColour[index] ?
(<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="w-6 h-6">
<path strokeLinecap="round" strokeLinejoin="round" d="M4.5 12.75l6 6 9-13.5" />
</svg>
) : (null)}
</button>
)
})}
</div>
<div className='counter'>
<button onClick={handleIncrement} disabled={singleProduct.quantity >= 10}>
+
</button>
<p>{singleProduct.quantity}</p>
<button onClick={handleDecrement} disabled={singleProduct.quantity <= 0}>
-
</button>
</div>
<button onClick={() => dispatch({ type: 'ADD', payload: singleProduct })}>Add to basket</button>
</div>
}
</div >
</>
)
}
export default Product
<!-- end snippet -->
When I console.log (updatedNum) after each increment button, it shows that it increments but when I do it for newQuantity it does not!
I have already tried:
const updatedNum = { ...newQuantity, quantity: newQuantity.quantity+1 }
but it always returns NaN
I've also put {newQuantity.quantity} and {singleProduct.quantity} in my JSX to see. It seems newQuantity has a delay and is one count behind the singleProduct
Would really appreciate some help working around this!
答案1
得分: 0
你的代码可能存在以下几个问题:
- 在实际增加之前,你记录了 newQuantity。
- 如果你在增加后立即写入
console.log(newQuantity)
,这不会解决问题,因为 React 状态更改是异步的。无论如何,这应该在多次点击后显示更改的值。 - 当你使用
counter++
符号时,这意味着变量将被递增,但它会返回先前的值。 - 你应该在组件中的 HTML 标记中使用状态(newQuantity)而不是 singleProduct。
为了使它正常工作,你应该将这个代码:
const handleIncrement = () => {
const updatedNum = { ...singleProduct, quantity: singleProduct.quantity ++ }
console.log(updatedNum)
console.log(newQuantity)
setNewQuantity(updatedNum)
}
更改为:
const handleIncrement = () => {
const updatedNum = { ...newQuantity, quantity: (newQuantity.quantity || 0) + 1 }
console.log(updatedNum)
setNewQuantity(updatedNum)
}
这将不会打印更改后的值,但界面应该按需工作。
为了避免编写 (newQuantity.quantity || 0) + 1
,并且只写 newQuantity.quantity + 1
,你可以将状态初始化更改为:
const [newQuantity, setNewQuantity] = useState({quantity: 0, ...singleProduct})
英文:
You can have several problems with your code:
- You log newQuantity just before your actual increment
- If you'll write
console.log(newQuantity)
just after increment it will not fix the problem cause react state change work asynchronously. Anyway, this should show changed value after multiple clicks. - When you use
counter++
notation it means that variable will be incremented but it returns previous value. - You should use state (newQuantity) inside html markup in component instead of singleProduct.
To make it work you should change this:
const handleIncrement = () => {
const updatedNum = { ...singleProduct, quantity: singleProduct.quantity ++ }
console.log(updatedNum)
console.log(newQuantity)
setNewQuantity(updatedNum)
}
to this
const handleIncrement = () => {
const updatedNum = { ...newQuantity, quantity: (newQuantity.quantity || 0) + 1 }
console.log(updatedNum)
setNewQuantity(updatedNum)
}
It will not print changed value but interface should work as needed.
To avoid writing (newQuantity.quantity || 0) + 1
and write just newQuantity.quantity + 1
you can change your state initialization to this:
const [newQuantity, setNewQuantity] = useState({quantity: 0, ...singleProduct})
答案2
得分: 0
没有测试过这个,但问题可能在于你在handleIncrement和handleDecrement函数中更新数量的方式。在React中,直接在singleProduct.quantity上使用++和--不太合适。而是应该这样做:
const handleIncrement = () => {
setNewQuantity(prevQuantity => ({
...singleProduct,
quantity: prevQuantity.quantity + 1
}));
};
const handleDecrement = () => {
setNewQuantity(prevQuantity => ({
...singleProduct,
quantity: prevQuantity.quantity - 1
}));
};
在这里,我们使用了setNewQuantity
,它接受一个回调函数,该函数获取先前的数量(prevQuantity
),然后我们通过展开singleProduct
并将数量设置为prevQuantity.quantity +/- 1
来创建一个新对象。
希望对你有所帮助!
英文:
Havn't tested this, but the problem could be how you're updating the quantity in the handleIncrement and handleDecrement functions. Using ++ and -- directly on singleProduct.quantity doesn't work well in React. Instead, do it like so:
const handleIncrement = () => {
setNewQuantity(prevQuantity => ({
...singleProduct,
quantity: prevQuantity.quantity + 1
}));
};
const handleDecrement = () => {
setNewQuantity(prevQuantity => ({
...singleProduct,
quantity: prevQuantity.quantity - 1
}));
};
Here we use setNewQuantity
with a callback function that takes the previous quantity (prevQuantity
) and then we create a new object by spreading singleProduct and setting quantity to prevQuantity.quantity +/- 1.
Hope it helps!
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论