Javascript onChange未触发useEffect

Javascript onChange未触发useEffect,javascript,reactjs,Javascript,Reactjs,我在OrderContent组件中收到一些道具上的产品,以便在select组件中使用它们,当我在select it renders Summary和product components中选择产品时,我可以在这些组件中选择数量,并使用这些数量计算OrderContent组件上的全部总数,问题是,当我尝试在输入类型(产品组件)中使用OnChange时,useffect(内部是计算状态中的总数的函数)不会触发,但如果我从状态中添加或删除产品,它会触发 import React, { Fragment,

我在OrderContent组件中收到一些道具上的产品,以便在select组件中使用它们,当我在select it renders Summary和product components中选择产品时,我可以在这些组件中选择数量,并使用这些数量计算OrderContent组件上的全部总数,问题是,当我尝试在输入类型(产品组件)中使用OnChange时,useffect(内部是计算状态中的总数的函数)不会触发,但如果我从状态中添加或删除产品,它会触发

import React, { Fragment, useState, useEffect } from "react";
import Select from "react-select";
import Animated from "react-select/lib/animated";
import Summary from './Summary';

function OrderContent({ products }) {

  const [productsSelected,setProductsSelected] = useState([]);
  const [total,setTotal] = useState(0);

  useEffect(() => {
    updateTotal()
  }, [productsSelected]);

  const selectProduct = (prod)=>{
    setProductsSelected(prod)
  }  

  const updateQuantity = (val,index)=>{
    const tempProds = productsSelected;
    tempProds[index].quantity= Number(val);
    setProductsSelected(tempProds)
  }  

  const deleteProduct = (id) =>{
    const tempProds = productsSelected;
    const remProds = tempProds.filter((p)=> p.id !== id );
    setProductsSelected(remProds);
    }

  const updateTotal = () =>{
    const tempProds = productsSelected;
    if(tempProds.length === 0){
      setTotal(0)
      return;
    }
    let newTotal = 0;
    tempProds.map((p)=>{
      const q = p.quantity ? p.quantity : 0;
      newTotal = newTotal + (q * p.price)
    })
    setTotal(newTotal)
  }

  return (
    <Fragment>
      <h2 className="text-center mb-5">Select Products</h2>
      <Select
        onChange={selectProduct}
        options={products}
        isMulti={true}
        components={Animated()}
        placeholder={"Select products"}
        getOptionValue={options => options.id}
        getOptionLabel={options => options.name}
        value={productsSelected}
      />
      <Summary
        products={productsSelected}
        updateQuantity={updateQuantity}
        deleteProduct = {deleteProduct}
      />
      <p className="font-weight-bold float-right mt-3">
      Total:
        <span className="font-weight-normal">
          ${total}
        </span>
      </p>
    </Fragment>
  );
}

export default OrderContent;


import React, {Fragment} from 'react';
import Product from './Product';

function Summary({products,updateQuantity,deleteProduct}) {

    if(products.length === 0) return null;


    return (
        <Fragment>
        <h2 className="text-center my-5">Summary and Quantities</h2>
        <table className="table">
            <thead className="bg-success text-light">
                <tr className="font-weight-bold">
                    <th>Product</th>
                    <th>Price</th>
                    <th>Inventory</th>
                    <th>Quantity</th>
                    <th>Delete</th>
                </tr>
            </thead>
            <tbody>
                {products.map((p,index)=>{
                    return (<Product
                            key={p.id}
                            id={p.id}
                            product={p}
                            index={index}
                            updateQuantity={updateQuantity}
                            deleteProduct={deleteProduct}
                        />)
                })}
            </tbody>
        </table>
        </Fragment>
    )
}

export default Summary



import React, { Fragment } from "react";

function Product({ product, updateQuantity, index, deleteProduct }) {
  return (
    <Fragment>
      <tr>
        <td>{product.name}</td>
        <td>${product.price}</td>
        <td>{product.stock}</td>
        <td>
          <input
            type="number"
            className="form-control"
            onChange={e => updateQuantity(e.target.value, index)}
          />
        </td>
        <td>
          <button type="button" className="btn btn-danger font-weight-bold" onClick={e=> deleteProduct(product.id)}>
            &times; Delete
          </button>
        </td>
      </tr>
    </Fragment>
  );
}

export default Product;
import React,{Fragment,useState,useffect}来自“React”;
从“反应选择”导入选择;
从“react select/lib/Animated”导入动画;
从“./Summary”导入摘要;
函数OrderContent({products}){
常量[productsSelected,setProductsSelected]=useState([]);
const[total,setTotal]=useState(0);
useffect(()=>{
updateTotal()
},[所选产品];
const selectProduct=(prod)=>{
已选择设置产品(产品)
}  
常量updateQuantity=(val,index)=>{
const tempProds=已选择的产品;
临时产品[索引]。数量=数量(val);
已选择设置产品(临时产品)
}  
常量deleteProduct=(id)=>{
const tempProds=已选择的产品;
const remProds=tempProds.filter((p)=>p.id!==id);
选择设置产品(remProds);
}
const updateTotal=()=>{
const tempProds=已选择的产品;
如果(tempProds.length==0){
setTotal(0)
返回;
}
设newTotal=0;
临时产品映射((p)=>{
常数q=p.数量?p.数量:0;
新总计=新总计+(q*p.价格)
})
setTotal(新总数)
}
返回(
精选产品
options.id}
getOptionLabel={options=>options.name}
值={productsSelected}
/>

总数: ${total}

); } 导出默认订单内容; 从“React”导入React,{Fragment}; 从“./产品”导入产品; 函数摘要({products,updatequality,deleteProduct}){ if(products.length==0)返回null; 返回( 摘要和数量 产品 价格 库存 量 删除 {products.map((p,index)=>{ 返回() })} ) } 导出默认摘要 从“React”导入React,{Fragment}; 函数乘积({Product,updatequality,index,deleteProduct}){ 返回( {product.name} ${product.price} {product.stock} updateQuantity(e.target.value,index)} /> deleteProduct(product.id)}> &时间;删除 ); } 导出默认产品;
updateQuantity
处于变异状态。这意味着react将看到您尝试使用相同的对象引用更新状态,并且将跳过重新渲染,这意味着没有
useffect
触发器

将其更改为此以使用新嵌套对象创建新阵列:

const updatequality=(val,index)=>{
const tempProds=[…productsSelected.map(val=>{…val})];
临时产品[索引]。数量=数量(val);
已选择设置产品(临时产品)
}
deleteProduct
不会变异,因为
filter
返回一个新数组。但是设置
temprods
是完全没有必要的

updateTotal
也会改变状态,但只会改变其嵌套对象。因此,这仍然需要修复,但可能不会导致相同的重新渲染问题


基于在多个地方使用了
const tempProds=products selected
,我认为您应该研究一下如何分配和引用JavaScript对象。有很多资源,但我写了一个相当详细的解释作为其中的一部分。

如果选择的产品是同一个数组,那么useEffect无法检测到更改,因为它总是指向同一个对象

const selectProduct = (prod)=>{
  setProductsSelected([...prod])
}  

强制所选产品成为新阵列

谢谢!它的工作,我也会阅读你给我的答案。