【问题标题】:setState not updating the state objectsetState 不更新状态对象
【发布时间】:2019-05-31 08:25:03
【问题描述】:

我正在从全栈反应这本书中学习反应。在其中一个示例投票应用程序中,您有产品和为产品投票的按钮。该按钮应该增加该产品的投票数,我将投票数存储在组件父状态中并将其显示在子组件中。该投票功能不起作用。

我创建了父组件,它显示了显示产品描述、ID、颜色和投票(产品收到的投票数)的子组件

import React, { Component } from 'react';
import './App.css';
import Product from "./Product";

var products = [
  {
    id: 1,
    name: "one",
    color: "blue",
    votes:0
  },
  {
    id: 2,
    name: "two",
    color: "green",
    votes : 0
  },
  {
    id: 3,
    name: "three",
    color: "Red",
    votes : 1
  }
];

class App extends Component {

  //this function will be passed to child component so the child can pass any data needed back to the parent using function argument.
  handleProductUpVote(productId) {
    console.log("Product #" + " " +productId + " was upvoted")
  };

  render() {
    const productComponents = products.map((product) => {
      return <Product
        key={"product-" + product.id}
        id={product.id}
        name={product.name}
        color={product.color}
        votes={product.votes}
        /*this is how we pass the function from parent to the child as a prop*/
        onVote={this.handleProductUpVote}
      />
    });
    return (
      <div className="App">
        {productComponents}
      </div>
    );
  }
}

export default App;

这是我的子组件,它在其中呈现产品详细信息

import React, { Component } from 'react';

class Product extends Component {
  constructor(props) {
    super(props);
    this.handleUpVote = this.handleUpVote.bind(this);
  }

  //using the function passed from parent in a child. We pass any data needed back to parent component using parent's function arugments 
  // invoke this function using onClick event inside the button 
  handleUpVote() {
    this.props.onVote(this.props.id);
  };

  render() {
    return (
      <div>
        <p> name: {this.props.name} </p>
        <p> MYcolor: {this.props.color} </p>
        {/*invoke the function using onClick so it will invoke handleUpVote that will update the prop and pass the data back to parent*/}
        <button onClick={this.handleUpVote}> Upvote Me </button>
        <p>{this.props.votes}</p>
        <hr></hr>
      </div>
    )
  }
};

export default Product;

这是有效的,当我点击“Upvoteme”按钮时,我将消息记录到控制台

但是当我试图将设置移动到使用状态时。它不起作用这是带有状态和setState的父组件。当我点击投票按钮时,投票计数没有任何变化。

import React, { Component } from 'react';
import './App.css';
import Child from "./Child";

var productseed = [
  {
    id: 1,
    name: "one",
    color: "blue",
    votes: 0
  },
  {
    id: 2,
    name: "two",
    color: "green",
    votes : 0
  },
  {
    id: 3,
    name: "three",
    color: "Red",
    votes : 1
  }
];

class Parent extends Component {
  constructor(props) {
    super(props);

    this.state = {
        products: [],
    };

    this.handleProductUpVote = this.handleProductUpVote.bind(this);
  }

  componentDidMount() {
    this.setState ({ products: productseed });
  }

  //this function will be passed to child component so the child can pass any data needed back to the parent using function argument.
  handleProductUpVote(productId) {
    // updating the vote in state
    const nextProducts = this.state.products.map((product) => {
      if (product.id === productId) {
        return Object.assign({}, product, {
          votes: product.votes + 1,
        });
      } else {
        return product
      }
    });

    this.setState({
      products: nextProducts,
    });
  }

  render() {
    const productComponents = productseed.map((product) => {
      return <Child
        key={"product-" + product.id}
        id={product.id}
        name={product.name}
        color={product.color}
        votes={product.votes}
        /*this is how we pass the function from parent to the child as a prop*/
        onVote={this.handleProductUpVote}
      />
    });

    return (
      <div className="App">
        parent
        {productComponents}
      </div>
    );
  }
}

export default Parent;

下面的行假设指向状态中的产品,但是当我突出显示它时,它并没有突出显示 this.state 中的产品。

控制台日志将消息记录到我的开发者控制台。这就是问题所在,this.setState 中的产品没有指向 this.state.products,因此没有更新状态。

componentDidMount() {
  this.setState({ products: productseed });
  console.log("this products not pointing to the this.state.products, why?")
}   

我阅读了关于 stackoverflow 的所有与 setState 不起作用相关的问题,但我遇到了同样的问题。如果您是一位能够做出反应并能够查看此问题并找出问题所在的专家,我将不胜感激。我无法弄清楚我何时分配了 this.setState({products: productseed}) 并且它没有更新状态。我花了近 4 个小时阅读和研究,请帮助。

【问题讨论】:

  • 如果您将此 console.log console.log("this products not pointing to the this.state.products, why?") 移动到 render() 中,您会看到预期的结果吗?另外,什么是日志记录?如果它不是指向状态中的产品,它指向什么?
  • 记住setState是异步的,所以如果你调用setState然后立即调用console.log之类的东西,状态可能还没有改变......这就是@HolyMolyreccomends的原因而是登录渲染。见docs
  • 当您的子组件运行它的回调函数onVote 时,它会更新父组件的状态。状态更改会触发重新渲染。我不确定,但我很确定因为组件正在重新渲染,所以所有生命周期事件循环,包括componentDidMount,在您的情况下将this.state.products 的值设置为seedProducts ...@987654335 @

标签: reactjs setstate


【解决方案1】:

您的问题在于您的Parent 组件的渲染方法。您正在迭代 productseeds 数组而不是您的状态。由于您正在更新状态而不是种子数组,因此 react 没有理由重新渲染任何内容,因此没有任何变化。

所以如果你改变那行

const productComponents = productseed.map((product) => {...

const productComponents = this.state.products.map((product) => {...

你应该没事的。

另外关于你的:

下面的行假设指向状态中的产品,但是当我突出显示它时,它并没有突出显示 this.state 中的产品。

这只是与您正在使用的 IDE 相关的内容,与 react 无关。您正在传递一个具有属性的对象,并且大多数 IDE(或所有(?))不会将带有 this.setState 的组合连接到状态对象。

【讨论】:

  • 谢谢。它确实在你的帮助下工作。我很感激。所以要理解这一点:按照你说的做之后,我现在从状态中提取数据,并使用 handleProductUpVote 函数更新状态。那么问题来了:为什么要使用 compnentDidMount 方法?我阅读了该方法并理解它,我质疑使用的原因,因为我从 productComponents 中提取数据来构建我的界面,然后单击按钮,在 handleProductUpVote 函数结束时我使用 this.setState 更新它与投票新状态。
  • 如果我去掉componentDidMount,整个界面就消失了。
  • 不客气。当您从外部源获取数据和/或初始状态为空时,您应该使用componentDidMount。原因是 this.setState 是一种异步方法,并且 react 不承诺“立即”更新状态。您可以删除 componentDidMount 方法并将初始状态设置为您的产品种子。但是你还是要使用this.state.products.map
  • 你的回答太准确了。它反映了你对 React 的深刻理解。新年快乐,谢谢。感谢是我所能提供给你的,但希望我能在不久的将来支付它。
猜你喜欢
  • 1970-01-01
  • 2021-01-28
  • 2018-04-08
  • 1970-01-01
  • 2018-10-14
相关资源
最近更新 更多