【问题标题】:useEffect not triggered by onChangeonChange 未触发 useEffect
【发布时间】:2020-02-13 03:18:32
【问题描述】:

我在 OrderContent 组件中的 props 上接收一些产品以在选择组件中使用它们,当我在选择中选择产品时,它会呈现摘要和产品组件,在这些组件中我可以选择数量并且我可以计算总计全部返回 OrderContent 组件,问题是当我尝试在输入类型中使用 OnChange(在 Product 组件上)时,useEffect(内部是计算状态总计的函数)不会触发,但如果我从该州添加或删除产品。

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;

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

    updateQuantity 处于变异状态。这意味着 react 将看到您尝试使用相同的对象引用更新状态,并且将跳过重新渲染,这意味着没有 useEffect 触发器。

    将其更改为此以创建具有新嵌套对象的新数组:

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

    deleteProduct 不会发生变异,因为filter 返回一个新数组。但是设置tempProds 是完全没有必要的。

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

    基于const tempProds = productsSelected在几个地方的使用,我认为你应该研究一下JavaScript对象是如何分配和引用的。那里有很多资源,但我写了一个非常详细的解释作为this answer 的一部分。

    【讨论】:

    • 谢谢!它的工作原理,我也会阅读你发给我的答案。
    【解决方案2】:

    如果 productsSelected 是同一个数组,则 useEffect 无法检测到更改,因为它始终指向同一个对象

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

    强制选择的产品为新数组

    【讨论】:

      猜你喜欢
      • 2013-08-07
      • 2021-03-05
      • 2021-12-16
      • 2017-11-01
      • 2021-12-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多