В чем причина этой задержки при изменении значения переменных состояния?

#reactjs

#reactjs

Вопрос:

Имея следующий код, я надеюсь, что при изменении значения цены и количества статус продуктов изменяется в родительском компоненте, это работает частично, потому что есть задержка в обновлении информации, я должен записать дважды значение цены и количества, чтобы увидеть какой-то результат. В чем причина этой задержки при изменении значения переменных состояния?

 import React, { useState } from "react";

const initialState = [
  {
    id: 1,
    name: "Nintendo switch",
    price: 250,
    quantity: 0,
    subTotal: 0
  },
  {
    id: 2,
    name: "Nintendo 3DS",
    price: 199,
    quantity: 0,
    subTotal: 0
  },
  {
    id: 3,
    name: "playstation 4",
    price: 300,
    quantity: 0,
    subTotal: 0
  }
];

function Totals({ products }) {
  function getTotal(key) {
    return products.reduce((previousValue, currentValue) => {
      return (previousValue  = currentValue[key]);
    }, 0);
  }

  return (
    <tr>
      <td />
      <td>{getTotal("price")}</td>
      <td>{getTotal("quantity")}</td>
      <td>{getTotal("subTotal")}</td>
    </tr>
  );
}

function Product({ product, onChange }) {
  const [price, setPrice] = useState(product.price);
  const [quantity, setQuantity] = useState(product.quantity);

  function onChangePrice(event) {
    setPrice(event.target.value);

    onChange({ id: product.id, price, quantity });
  }

  function onChangeQuantity(event) {
    setQuantity(event.target.value);

    onChange({ id: product.id, price, quantity });
  }

  return (
    <tr>
      <td>{product.name}</td>
      <td>
        <input onChange={onChangePrice} value={price} />
      </td>
      <td>
        <input onChange={onChangeQuantity} value={quantity} />
      </td>
      <td>{product.subTotal}</td>
    </tr>
  );
}

function App() {
  const [products, setProducts] = useState(initialState);

  function onChangeHandler(entry) {
    const output = products.map(product =>
      product.id === entry.id
        ? {
            ...product,
            price:  entry.price,
            quantity:  entry.quantity,
            subTotal:  entry.price *  entry.quantity
          }
        : product
    );

    setProducts(output);
  }

  return (
    <table>
      <thead>
        <tr>
          <th>Name</th>
          <th>Price</th>
          <th>Quantity</th>
          <th>Sub total</th>
        </tr>
      </thead>
      <tbody>
        {products.map(product => (
          <Product
            key={product.id}
            product={product}
            onChange={onChangeHandler}
          />
        ))}
        <Totals products={products} />
      </tbody>
    </table>
  );
}

export default App;
  

Пожалуйста, взгляните на этот пример

https://codesandbox.io/s/gracious-ride-tixs1

Ответ №1:

Проблема в том, что вы по существу сохраняете состояние в 2 местах, и они не всегда согласуются. Product Компонент должен быть без состояния, поскольку вы поддерживаете состояние в своем списке продуктов.

 function Product({ product, onChange }) {

  function onChangePrice(e) {
    onChange({ id: product.id, price: e.target.value, quantity: product.quantity });
  }

  function onChangeQuantity(e) {
    onChange({ id: product.id, quantity: e.target.value, price: product.price });
  }

  return (
    <tr>
      <td>{product.name}</td>
      <td>
        <input onChange={onChangePrice} value={product.price} />
      </td>
      <td>
        <input onChange={onChangeQuantity} value={product.quantity} />
      </td>
      <td>{product.subTotal}</td>
    </tr>
  );
}
  

Ответ №2:

Хотя Product локальные price и quantity установлены правильно, вы вызываете onChange , который является реквизитом, переданным родительским компонентом, со старыми значениями:

 function onChangePrice(event) {
  setPrice(event.target.value);

  onChange({ id: product.id, price, quantity });
}

function onChangeQuantity(event) {
  setQuantity(event.target.value);

  onChange({ id: product.id, price, quantity });
}
  

Если вам действительно нужно по какой-либо причине сохранить цену и количество в дочернем компоненте, а также в родительском компоненте, обязательно вызывайте onChange с event.target.value вместо старых значений в price и quantity :

 function onChangePrice(event) {
  setPrice(event.target.value);

  onChange({ id: product.id, price: event.target.value, quantity });
}

function onChangeQuantity(event) {
  setQuantity(event.target.value);

  onChange({ id: product.id, price, quantity: event.target.value });
}