【问题标题】:React unable to rerender after setState using Fetch使用 Fetch 在 setState 后 React 无法重新渲染
【发布时间】:2017-10-11 05:56:38
【问题描述】:

我已经束手无策了。我是一名编码新手,尝试使用 .map() 遍历 JSON 数据并将其显示在 React 的卡片中。

我在 componentDidMount() 下获取数据并使用 setState 来分配它。这在另一个页面上完全可以正常工作。

但是,在此页面上,我尝试遍历此对象上的“项目”数组,但每当我尝试将 .map() 放入产品数组时,都会出错。

即使是简单的console.log,我也会遇到错误。

我认为这与异步获取有关,但我看到的所有问题都使用 setState() 解决了这个问题。我不知道该怎么办。

这是我的 JSON 对象:

    {
    "_id": "59dac308b9267fbcb5d2de32",
    "name": "The Jewelry Counter",
    "description": "Limited edition fine jewelry, handcrafted in the USA",
    "image": "/public/images/tjclogo.png",
    "__v": 0,
    "products": [
        {
            "_id": "59dada32b9267fbcb5d2de37",
            "name": "Opal and cubic zirconia stacking ring set",
            "price": 80,
            "description": "A three ring stacking set that features an arced ring with an opal and cz, one with just glowing cz's and one with a single solitaire prong set opal.",
            "img": "/shopping-cart-app/public/images/ringset.png",
            "quantity": 2,
            "__v": 0,
            "keywords": [
                "ring",
                "opal",
                "cubic zirconia",
                "cz",
                "jewelry",
                "womens",
                "jewelry counter"
            ]
        },
        {
            "_id": "59dadae1b9267fbcb5d2de38",
            "name": "Moonstone Ear Jackets",
            "price": 140,
            "description": "Four teardrop shaped glowing moonstones are prong set and attach to your ear in a simple three piece process that makes it look as though they are floating on your ears.",
            "img": "/shopping-cart-app/public/images/moonearrings.png",
            "quantity": 4,
            "__v": 0,
            "keywords": [
                "earrings",
                "moonstone",
                "jewelry",
                "womens",
                "jewelry counter"
            ]
        },
        {
            "_id": "59dadb79b9267fbcb5d2de39",
            "name": "Horizontal Pyrite Necklace",
            "price": 52,
            "description": "A horizontal bar of hand crushed pyrite is attached to a brass bar on a 16\" brass chain.",
            "img": "/shopping-cart-app/public/images/pyritenecklace.jpg",
            "quantity": 1,
            "__v": 0,
            "keywords": [
                "necklace",
                "pyrite",
                "jewelry",
                "womens",
                "jewelry counter"
            ]
        },
        {
            "_id": "59dadcfbb9267fbcb5d2de3a",
            "name": "Purple Tourmaline Promise Rings",
            "price": 48,
            "description": "Faceted purple tourmaline prong set on an 18K yellow gold vermeil band. This simple ring is perfect for stacking.",
            "img": "/shopping-cart-app/public/images/ring.jpg",
            "quantity": 1,
            "__v": 0,
            "keywords": [
                "ring",
                "tourmaline",
                "jewelry",
                "womens",
                "jewelry counter"
            ]
        }
    ]
}

我有以下代码:

import React, { Component } from 'react';
import StoreCard from '../../StoreCard';
import ProductCard from '../../ProductCard';
import Wrapper from '../../Wrapper';
import Header from '../../Header';
import StoreLogin from "../../StoreLogin";
import Store from "../../Store";
import './Shop.css';

class Shop extends Component {

  constructor(props) {
        super(props);
        this.state = { storeInfo: []};

    }

    // state = {storeInfo: [], 
        // products: []
    // };

   componentDidMount() {
    fetch('/stores/59dac308b9267fbcb5d2de32')
        .then(res => res.json())
        .then((storeInfo) => {this.setState({ storeInfo: storeInfo })})
   }






  render() {
    console.log(this.state.storeInfo) // works,displays the entire JSON object after beig called twice in the console.
    console.log(this.state.storeInfo.name); // WORKS, same as above
    console.log(this.state.storeInfo['products'][1]['name']); //DOES NOT WORK - ERRORS
    // console.log(this.state.storeInfo.products[1].name); //DOES NOT WORK - ERRORS

    return (
     <div>
        <Header location="Search all stores"/>
        <Wrapper>

          <StoreLogin
            id={this.state.storeInfo._id} // works
            userName={this.state.storeInfo.name} // works
            // productName={this.state.storeInfo.products[1].name} //does not work
          >






            </StoreLogin>

      </Wrapper>
      <h1>Shop</h1>
      </div>
    );
  }
}


export default Shop;

当我一次取消注释 storeLogin 组件中的“console.logs”和“productName”时,我收到 3 个错误:

Uncaught TypeError: Cannot read property '1' of undefined

然后

proxyConsole.js:54 The above error occurred in the <Shop> component:
    in Shop (created by Route)
    in Route (at App.js:22)
    in div (at App.js:19)
    in Router (created by BrowserRouter)
    in BrowserRouter (at App.js:17)
    in App (at index.js:6)

Consider adding an error boundary to your tree to customize error handling behavior.
You can learn more about error boundaries at https://reactjs.org/blog/2017/07/26/error-handling-in-react-16.html

然后

Uncaught TypeError: Cannot read property '1' of undefined

再次。

【问题讨论】:

  • 它会抛出什么错误?
  • 当提取结果为单个对象时,为什么要将 storeInfo 初始化为空数组?
  • @pritesh 我更新了我的原始问题以显示我的错误,感谢您的时间!
  • @RamanKumarSharma 我想我必须这样做,因为它是一个对象而不是字符串,谢谢你指出我没有。

标签: json reactjs fetch render setstate


【解决方案1】:

原因是您尝试访问 storeInfo['products'][1]['name'] 的数据最初在渲染函数中尚不可用。因此您需要检查数据是否存在。为此您能做的就是

render() {
    console.log(this.state.storeInfo.name); // WORKS

    //Move this console inside if
    if ( this.state.storeInfo.products && this.state.storeInfo.products.length) {
        console.log(this.state.storeInfo['products'][1]['name']);
        console.log(this.state.storeInfo.products[0].name); 
    }

    return (
    <div>
        <Header location="Search all stores"/>
        <Wrapper>

        <StoreLogin
            id={this.state.storeInfo._id} // works
            userName={this.state.storeInfo.name} // works
             productName={this.state.storeInfo.products && this.state.storeInfo.products.length &&
 this.state.storeInfo.products[0].name} //<-- Same here
        >
        </StoreLogin>
    </Wrapper>
    <h1>Shop</h1>
    </div>
    );
}

【讨论】:

  • Pritesh!你是救生员!这行得通。无论如何将其放入 .map() 方法中?喜欢{this.state.storeInfo.products.map(product) =&gt; &lt; iPutMyCardInHere /&gt; }
  • 是的,你可以这样做this.state.storeInfo.products.map((product) =&gt; &lt; iPutMyCardInHere /&gt;)
  • 哦哈利路亚!我让它工作。我不明白如果在设置状态后组件应该重新渲染,为什么我必须这样做?是不是时间太长了?
  • 对于任何寻找的人:{this.state.storeInfo.products &amp;&amp; this.state.storeInfo.products.length &amp;&amp; this.state.storeInfo.products.map((product) =&gt;&lt;iPutMyCardInHere /&gt;)} 允许我将我的道具传递为卡片中的product.keyName
【解决方案2】:

问题是,您在 componentDidMount 函数中有一个 fetchRequest,然后设置状态,但是在它之前调用了您的渲染,并且由于您尝试访问 this.state.storeInfo.products[0].namethis.state.storeInfo.products 未定义,因此您得到一个错误,使用前请检查

return (
 <div>
    <Header location="Search all stores"/>
    <Wrapper>

      <StoreLogin
        id={this.state.storeInfo._id} // works
        userName={this.state.storeInfo.name} // works
        productName={this.state.storeInfo.products && his.state.storeInfo.products[0]?
         this.state.storeInfo.products[0].name: ''} 
      >

【讨论】:

    猜你喜欢
    • 2019-09-26
    • 1970-01-01
    • 2016-12-11
    • 2021-04-28
    • 2017-04-19
    • 2019-08-10
    • 1970-01-01
    • 1970-01-01
    • 2020-01-22
    相关资源
    最近更新 更多