1

What I am trying to do: I need price * quantity = total. I have a table with price as one , quantity as one and total as one . Quantity is a counter and needs to have its own state as rows will be added with more counters. But I need that value in the parent table so I can use it to calculate total.

Normally I would put the counter value in the parent, but if I do that, when I change one counter they all change. So how else can I pass the value back up to the parent? Or what other option do I have here.

//parent
const memoData = useMemo(() => {
    return productList.map((product) => (
      <tr key={product.productNumber} className='productTable__row'>
        <td>
          <input
            placeholder='Product name'
            className='productTable__input productTable__input_product'
            defaultValue={product.productName}
          />
        </td>

        <td>
          <input
            placeholder='Id'
            className='productTable__input productTable__input_id'
            disabled
            defaultValue={product.productNumber}
          />
        </td>
        <td>
          <input
            placeholder='Price'
            className='productTable__input productTable__input_price'
            defaultValue={product.price}
          />
        </td>
        <td>
          <Input prouct={product} />
        </td>
        <td>
          <input
            placeholder='Total'
            className='productTable__input productTable__input_price'
            defaultValue={? * product.price}
          />
        </td>
        <td>
          <button
            className='productTable__btn_close'
            onClick={() => onProductDelete(product)}
          >
            <RiCloseFill fill='red' size='30px' />
          </button>
        </td>
      </tr>
    ));
  }, [onProductDelete, currentProduct, productList]);

//child
function Input() {
  const [counter, setCounter] = useState(1);

  const addOneClick = () => {
    setCounter(counter + 1);
  };

  const minusOneClick = () => {
    if (counter > 0) {
      setCounter(counter - 1);
    }
  };

  return (
    <div style={{ width: '88px' }}>
      <button
        className='productTable__btn_minus'
        style={{ borderRight: 'none' }}
        onClick={minusOneClick}
      >
        <FaMinus fill='var(--color-primary-blue)' size='14px' />
      </button>
      <input
        placeholder='0'
        className='productTable__input productTable__input_quantity'
        //   defaultValue={0}
        value={counter}
      />

      <button
        className='productTable__btn_plus'
        style={{ borderLeft: 'none' }}
        onClick={addOneClick}
      >
        <FaPlus fill='var(--color-primary-blue)' size='14px' />
      </button>
    </div>
  );
}

Visual ref: enter image description here

mike
  • 109
  • 2
  • 10

1 Answers1

1

You should consider productList as "the state" in the parent, instead of counter, and you should have counter as a property of product:

// productList
[
    {
        id: 123,
        counter: 0,           // <-- add a counter property
        productNumber: '...',
        // ...
    },
]

// parent
return productList.map( product => (
    <tr key={ product.productNumber } >
        <td>
            {/* add onSetCounter() callback */}
            <Input
                product={ product }
                onSetCounter={ id => { setCounter( id, count ); } }
            />
        </td>
    </tr>
));

// child
function Input() {
    const counter = props.product.counter;         // <-- use props
    const setCounter = props.setCounter;           // <-- use props
    // const [counter, setCounter] = useState(1);  // <-- don't use local state

    const addOneClick = () => {
        setCounter(counter + 1);
    };

    return (
        <button onClick={ addOneClick } >add one</button>
    );
}

// update the counter
const setCounter = function( id, count ){

    // ... I don't know how you are managing your productList.
    // I would put this code into my redux-reducer. ...

    const newProductList = productList.reduce( (acc, product) => {
        if( product.id === id ){ // current product
            acc.push({
                ...product,
                counter: count
            })
        } else {                 // other products
            acc.push( product );
        };
    }, []);

};

(I wrote props.product here, despite you are passing <Input prouct={...} />, I assume that was a typing mistake)

kca
  • 4,856
  • 1
  • 20
  • 41