开发者问题收集

React/redux:渲染嵌套对象属性时出错

2019-06-13
1446

我有一个通过 RabbitMQ 接收数据的 react/redux 前端。当消息到达时,我们的消息处理程序将分派一个操作,例如 PRODUCT_DETAILS_LOADED ,该操作会更新商店并使用产品详细信息呈现相应的组件。这 95% 有效,但如果我尝试显示嵌套对象属性,我会收到错误: 无法读取未定义的属性 <prop>

我对此做了一些研究。大多数答案都表明发生了竞争条件,并且组件试图在属性“准备好”之前呈现它们。我不明白为什么会这样,因为我没有进行 REST 调用;我已经从消息队列中获得了数据,并且已经更新了商店。此外, render 函数内的 console.log 将显示嵌套属性的正确值。这是我的 ProductDetails 组件的大部分内容:

const mapStateToProps = state => {
  return { product: state.productDetail };
}

class ProductDetails extends Component {

  render() {
    console.log(this.props.product.availability.forsale);  //This will correctly show 'true' or 'false'
    return (
            <div> 
                <h3>Product Details Page</h3>
                <h5>Details for {this.props.product.name}: </h5>
                <div>
                  Name:  {this.props.product.name}
                  <br/>
                  SKU:  {this.props.product.sku}
                  <br/>
                  Available:  {this.props.product.availability.forsale} //This throws an error
                  <br/> 
                  {/*Price: {this.props.product.price.$numberDecimal} //This would also throw an error
                  <br/>*/}
                  Description: {this.props.product.description}              
                </div>
                <Link to="/">Back to Home Page</Link> 
            </div>
    )
  }
}

const Details = connect(mapStateToProps, null)(ProductDetails);
export default Details;

这是收到产品详细信息消息时触发的处理程序的片段:

  } else if(json.fields.routingKey === 'product.request.get') {   
    if(json.status === 'success') {
     let payload = json.data;
      store.dispatch(productDetailsLoaded(payload));
    } 

这是分派操作的函数:

export function productDetailsLoaded(details) {
  return { type: PRODUCT_DETAILS_LOADED, productDetail: details }
}

最后,reducer:

  if(action.type === PRODUCT_DETAILS_LOADED) {
    return Object.assign({}, state, {
      productDetail: action.productDetail
    });
  }

我看到过一些答案,建议使用如下方法防止出现错误: let av = this.props.product.availability ? this.props.product.availability.forsale : ''; 。这对我来说不起作用。虽然它确实可以防止出现错误,但我将显示空白值。这对我来说不是一个选择;我必须在详细信息页面上显示正确的信息,而不仅仅是“不正确”的信息。

有人能帮我理解发生了什么吗?为什么 console.log 语句显示正确的数据,但 bomb 之后的 render 语句却显示错误?我该如何解决这个问题?

谢谢!

编辑:这是我尝试渲染的对象:

{ 
    assets: {
        imgs: "https://www.zzzzzzz.com/content/12626?v=1551215311"
    }
    availability: {
        forsale: true, 
        expires: "2025-12-29T05:00:00.000Z"
    }
    createdAt: "2015-01-25T05:00:00.000Z"
    description: "his is a fake description"
    modifiedAt: "2019-05-28T04:00:00.000Z"
    name: "Product Name"
    price: {
        $numberDecimal: "59.95"
    }
    sku: "ZZZZ"
    "title ": "Product Title"
    _id: "5ceec82aa686a03bccfa67cc"
}
1个回答

您正尝试在对象准备就绪之前访问它。抛出错误的两个地方是子属性。因此,对于其他所有内容,初始值都是“未定义”,您的应用程序对此没有问题,但是一旦它尝试读取未定义的属性,就会抛出错误。

有三种解决方案: 1) 确保组件在状态更新完成之前根本不加载。此逻辑将在 ProductDetails 的父组件中处理。

如果 1) 不是一个选项,请执行以下操作之一:

2) 在您的组件中设置 productDetails: null

render() {
    console.log(this.props.product.availability.forsale);  //This will correctly show 'true' or 'false'
    if (!this.props.product) return <div />;
    return (
            // what you have above
    )
  }
}

const Details = connect(mapStateToProps, null)(ProductDetails);
export default Details;

3) 设置默认状态形状,类似于:

{ 
    assets: {
        imgs: null
    }
    availability: {
        forsale: null, 
        expires: null
    }
    createdAt: null
    description: null
    modifiedAt: null
    name: null
    price: {
        $numberDecimal: null
    }
    sku: null
    "title ": null
    _id: null
}

这是 react 默认行为的一部分,也是 redux 问题。有关 setState 的工作原理以及为什么不应将其视为同步代码的更多信息,请参阅 https://reactjs.org/docs/react-component.html#setstate

Cal Irvine
2019-06-13