为什么要状态更新本身?不调用setState

时间:2018-07-28 08:54:04

标签: javascript reactjs ecmascript-6

我是React的初学者。面对一个问题不知道为什么。 使一组产品进入反应状态。

当用户单击按钮(通过子组件)时,我正在从状态克隆当前产品数组,然后对其进行修改,但是状态正在更新而不调用setState。 帮助真的很感激。我想知道为什么它会像这样。

这是App组件文件:

class App extends Component {
    constructor(props) {
        super(props);
        this.state = {
            products: [
                {
                    id: 1,
                    img: 'http://placehold.it/460x250/e67e22/ffffff&text=HTML5',
                    title: 'Laptop',
                    quantity: 1,
                    price: 250,
                },
            ],
            cart_products: [],
            total_price: 0,
            total_product: 0,
        };
    }

    addProductToCart = (id) => {
        let cartProducts = [];
        // Trying to clone first
        let productCopy = [...this.state.products];

        // Find specific product
        let newProduct = productCopy.find((item) => {
            return item.id === id;
        });

        // Now into new product I want to add some extra property
        newProduct['originalPrice'] = newProduct.price;

        // Here I want some other code.
        cartProducts.push(newProduct);

        this.setState({
            cart_products: cartProducts
        });
    }

    render() {
        return (
            <div className="container-fluid">
                <div className="container">
                    <h1 className="text-center">React.js Example </h1>
                </div>
                <div>
                    <div className="col-sm-6">
                        <Cart products={this.state.cart_products} totalPrice={this.state.total_price} totalProduct={this.state.total_product} />
                    </div>
                    <div className="col-sm-6">
                        <Products products={this.state.products} onClicked={this.addProductToCart} />
                    </div>
                </div>
            </div>
        );
    }
}

问题是“产品”阵列进入状态自动更新。这是React Chrome Extension的图片

在方法调用之前 enter image description here

方法调用后: enter image description here

应用程序的想法只是简单的购物车系统。当用户单击添加产品按钮时,我想将特定产品添加到购物车中。但是我被困在如何解决这个问题上。

3 个答案:

答案 0 :(得分:1)

我可以在行

看到一些问题
let productCopy = [...this.state.products];

只需将行替换为

let productCopy = JSON.parse(JSON.stringify([...this.state.products]))

为什么需要它?

这就是传播运算符在复制复杂变量时的工作方式。 这里是reference,其中

  

注意:复制文件时,传播语法有效地深入了一层   数组。因此,它可能不适合复制多维   数组如以下示例所示(与   Object.assign()和传播语法)。

答案 1 :(得分:1)

您可以使用传播对象语法来创建新属性,而不会在以下状态下更改原始对象:

  addProductToCart = (id) => {
    const { products, cart_products } = this.state;

    // Find the relevant product
    let relevantProduct = products.find((item) => {
      return item.id === id;
    });

    // Now into new product I want to add some extra property
    const newProduct= {
      ...relevantProduct,
      originalPrice: relevantProduct.price
    };

    this.setState({
      cart_products: [...cart_products, newProduct]
    });
  } 

运行示例:

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      products: [
        {
          id: 1,
          img: 'http://placehold.it/460x250/e67e22/ffffff&text=HTML5',
          title: 'Laptop',
          quantity: 1,
          price: 250,
        },
      ],
      cart_products: [],
      total_price: 0,
      total_product: 0,
    };
  }

  addProductToCart = (id) => {
    const { products, cart_products } = this.state;

    // Find the relevant product
    let relevantProduct = products.find((item) => {
      return item.id === id;
    });

    // Now into new product I want to add some extra property
    const newProduct = {
      ...relevantProduct,
      originalPrice: relevantProduct.price
    };

    this.setState({
      cart_products: [...cart_products, newProduct]
    });
  }

  render() {
    const { products, cart_products } = this.state;
    return (
      <div>
        <div>Cart</div>
        {
          cart_products.map((product, index) => <div key={index}>{product.title}</div>)
        }
        <hr />
        <div>Product list</div>
        {
          products.map((product, index) => (
            <div>
              <div key={index}>{product.title}</div>
              <button onClick={() => this.addProductToCart(product.id)}>Add</button>
            </div>)
          )
        }
      </div>
    )
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

答案 2 :(得分:0)

  

在JS对象中通过引用传递。

我不确定您是否已经知道这个事实,但是在JS中,我猜几乎所有编程语言的对象都是通过引用传递的。在您的代码中的以下行:

// Trying to clone first
 let productCopy = [...this.state.products];

...当然,您正在创建一个新数组productCopy,但是即使是新数组,也将具有与先前数组this.state.products相同的对象,而不是这些对象的某些克隆正如您所期望的。 您可以编写自己的代码来深度克隆对象和数组。或者,您可以使用一些非常好的JS库,例如lodash,如下所示:

var arr = [{a:1, b:2}, {c:3, d:4}]

var newArr = _.cloneDeep(arr);
newArr[0].e = 5;
console.log(arr[0]);
console.log(newArr[0]);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>