计数器使用UseState

huangapple go评论76阅读模式
英文:

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 &#39;react&#39;
import { Link, useParams } from &#39;react-router-dom&#39;
import { useState, useContext } from &#39;react&#39;
import GetSingleProduct from &#39;../Hooks/getSingleProduct&#39;
import { AppContext } from &#39;../Context/Context&#39;
import &#39;../Assets/Styles/Product.css&#39;
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) =&gt; {
setClickedColour(prevstate =&gt;
({
...prevstate, [index] // copies prev state
: !prevstate[index]
}))
console.log(setClickedColour)
}
const [newQuantity, setNewQuantity] = useState({...singleProduct})
const handleIncrement = () =&gt; {
const updatedNum = { ...singleProduct, quantity: singleProduct.quantity ++ }
console.log(updatedNum) 
console.log(newQuantity)
setNewQuantity(updatedNum)
}
const handleDecrement = () =&gt; {
setNewQuantity({ ...singleProduct, quantity:newQuantity.quantity-- })
}
return (
&lt;&gt;
&lt;div className=&#39;routeTaken&#39;&gt;
&lt;ol&gt;
&lt;li&gt;&lt;Link to=&#39;/&#39;&gt;Home&lt;/Link&gt;&lt;/li&gt;
&lt;li&gt;&lt;Link to=&#39;/shop&#39;&gt;Shop&lt;/Link&gt;&lt;/li&gt;
&lt;li&gt;Current page&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div className=&#39;productInfo&#39;&gt;
{error &amp;&amp; &lt;div&gt;{error}&lt;/div&gt;}
{isLoading ?
(&lt;div&gt;Loading...&lt;/div&gt;) :
&lt;div id={singleProduct.id}&gt;
&lt;img src={singleProduct.api_featured_image} alt={singleProduct.product_type}&gt;&lt;/img&gt;
&lt;p&gt;{singleProduct?.product_type ? singleProduct.product_type.charAt(0).toUpperCase() + singleProduct.product_type.slice(1).toLowerCase().split(&#39;_&#39;).join(&#39; &#39;) : singleProduct.product_type}&lt;/p&gt;
&lt;h1&gt;{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}&lt;/h1&gt;
&lt;h2&gt; &#163;{singleProduct.price===&#39;0.0&#39;||singleProduct.price === null ? &#39;8.50&#39;: Number(singleProduct.price).toFixed(2)}&lt;/h2&gt;
&lt;h3&gt;{singleProduct.description}&lt;/h3&gt;
&lt;div className=&quot;colourList grid grid-cols-4&quot;&gt;
{singleProduct.product_colors?.map((colour, index) =&gt; {
return (
&lt;button onClick={() =&gt; handleColour(index)} className=&#39;colourItem&#39; key={index} style={{ backgroundColor: colour.hex_value }}&gt;
{colour.hex_value}
{clickedColour[index] ?
(&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; fill=&quot;none&quot; viewBox=&quot;0 0 24 24&quot; strokeWidth={1.5} stroke=&quot;currentColor&quot; className=&quot;w-6 h-6&quot;&gt;
&lt;path strokeLinecap=&quot;round&quot; strokeLinejoin=&quot;round&quot; d=&quot;M4.5 12.75l6 6 9-13.5&quot; /&gt;
&lt;/svg&gt;
) : (null)}
&lt;/button&gt;
)
})}
&lt;/div&gt;
&lt;div className=&#39;counter&#39;&gt;
&lt;button onClick={handleIncrement} disabled={singleProduct.quantity &gt;= 10}&gt;
+
&lt;/button&gt;
&lt;p&gt;{singleProduct.quantity}&lt;/p&gt;
&lt;button onClick={handleDecrement} disabled={singleProduct.quantity &lt;= 0}&gt;
-
&lt;/button&gt;
&lt;/div&gt;
&lt;button onClick={() =&gt; dispatch({ type: &#39;ADD&#39;, payload: singleProduct })}&gt;Add to basket&lt;/button&gt;
&lt;/div&gt;
}
&lt;/div &gt;
&lt;/&gt;
)
}
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

你的代码可能存在以下几个问题:

  1. 在实际增加之前,你记录了 newQuantity。
  2. 如果你在增加后立即写入 console.log(newQuantity),这不会解决问题,因为 React 状态更改是异步的。无论如何,这应该在多次点击后显示更改的值。
  3. 当你使用 counter++ 符号时,这意味着变量将被递增,但它会返回先前的值。
  4. 你应该在组件中的 HTML 标记中使用状态(newQuantity)而不是 singleProduct。

为了使它正常工作,你应该将这个代码:

const handleIncrement = () =&gt; {
  const updatedNum = { ...singleProduct, quantity: singleProduct.quantity ++ }
  console.log(updatedNum) 
  console.log(newQuantity)
  setNewQuantity(updatedNum)
}

更改为:

const handleIncrement = () =&gt; {
  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:

  1. You log newQuantity just before your actual increment
  2. 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.
  3. When you use counter++ notation it means that variable will be incremented but it returns previous value.
  4. You should use state (newQuantity) inside html markup in component instead of singleProduct.

To make it work you should change this:

  const handleIncrement = () =&gt; {
    const updatedNum = { ...singleProduct, quantity: singleProduct.quantity ++ }
    console.log(updatedNum) 
    console.log(newQuantity)
    setNewQuantity(updatedNum)
  }

to this

  const handleIncrement = () =&gt; {
    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 = () =&gt; {
  setNewQuantity(prevQuantity =&gt; ({
    ...singleProduct,
    quantity: prevQuantity.quantity + 1
  }));
};

const handleDecrement = () =&gt; {
  setNewQuantity(prevQuantity =&gt; ({
    ...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!

huangapple
  • 本文由 发表于 2023年6月29日 19:22:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/76580562.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定