在使用 Fetch 的 setState 后反应无法重新呈现
React unable to rerender after setState using Fetch
我已经无计可施了。我是一名编码新手,尝试使用 .map() 遍历 JSON 数据并将其显示在 React 的卡片中。
我在componentDidMount()下取数据,用setState赋值。这在另一页上完全正常。
但是,在此页面上,我试图遍历此对象上的 'projects' 数组,但每当我尝试将 .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['products'][1]['name'] 的数据在呈现函数中尚不可用 initially.So 您需要检查是否数据是present.For,你能做的是
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>
);
}
问题是,您在 componentDidMount 函数中有一个 fetchRequest 然后设置状态,但是您的渲染在它之前被调用并且由于您尝试访问 this.state.storeInfo.products[0].name
,this.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: ''}
>
我已经无计可施了。我是一名编码新手,尝试使用 .map() 遍历 JSON 数据并将其显示在 React 的卡片中。
我在componentDidMount()下取数据,用setState赋值。这在另一页上完全正常。
但是,在此页面上,我试图遍历此对象上的 'projects' 数组,但每当我尝试将 .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['products'][1]['name'] 的数据在呈现函数中尚不可用 initially.So 您需要检查是否数据是present.For,你能做的是
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>
);
}
问题是,您在 componentDidMount 函数中有一个 fetchRequest 然后设置状态,但是您的渲染在它之前被调用并且由于您尝试访问 this.state.storeInfo.products[0].name
,this.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: ''}
>