我正在调用一个api,并通过响应设置状态。 我无法调用setState而不看到此错误: 如果setState发生在promise之外,则不会发生该错误。
如何将API响应设置为状态而不看到此错误?
无法在未安装的组件上调用setState(或forceUpdate)
componentDidMount() {
const url = 'https://localhost:8000/api/items'
let items;
fetch(url, {mode: 'cors'})
.then(res => res.json())
.then(
(result) => {
this.setState({
isLoaded: true,
items: result
});
},
(error) => {
this.setState({
isLoaded: true,
error
});
}
)
}
整个组件供参考:
import React, { Component } from 'react'
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';
import GridList from '@material-ui/core/GridList';
import GridListTile from '@material-ui/core/GridListTile';
import GridListTileBar from '@material-ui/core/GridListTileBar';
import ListSubheader from '@material-ui/core/ListSubheader';
import IconButton from '@material-ui/core/IconButton';
import InfoIcon from '@material-ui/icons/Info';
const styles = theme => ({
root: {
display: 'flex',
flexWrap: 'wrap',
justifyContent: 'space-around',
overflow: 'hidden',
backgroundColor: theme.palette.background.paper,
},
icon: {
color: 'rgba(255, 255, 255, 0.54)',
},
});
class ItemList extends Component {
constructor(props) {
super(props)
this.state = {
items: [],
isLoaded: false,
}
this.handleItemClick = this.handleItemClick.bind(this);
}
componentDidMount() {
const url = 'https://localhost:8000/api/items'
let items;
fetch(url, {mode: 'cors'})
.then(res => res.json())
.then(
(result) => {
this.setState({
isLoaded: true,
items: result
});
},
(error) => {
this.setState({
isLoaded: true,
error
});
}
)
}
handleItemClick(id) {
}
handleRenderItems() {
const { classes } = this.props
const { items } = this.state;
return this.state.items.map((item, idx) => {
const id = item.id;
return (
<GridListTile onClick={() => this.handleItemClick(id)} key={idx}>
<img src={item.key_image} alt={item.title} />
<GridListTileBar
title={item.title}
subtitle={<span>${item.rent_price_day}/day</span>}
actionIcon={
<IconButton className={classes.icon}>
<InfoIcon />
</IconButton>
}
/>
</GridListTile>
)
})
}
render() {
const { classes } = this.props;
return (
<div className={classes.root}>
<GridList cols={3} cellHeight={220} className={classes.gridList}>
<GridListTile key="Subheader" cols={3} style={{ height: 'auto' }}>
<ListSubheader component="div">Popular Items</ListSubheader>
</GridListTile>
{this.handleRenderItems()}
</GridList>
</div>
);
}
}
ItemList.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styles)(ItemList);
与其在组件中进行处理,不如在操作创建者中处理对API的调用,并使用redux存储数据,然后将其发送到组件(如果可用),可能会更简单。最好还是将这些细节保留在视图之外。
此外,通常也不会在视图中使用样式对象-但这是带有material-ui的样板。
答案 0 :(得分:3)
在组件内部添加以下内容,
componentDidMount() {
this.isMounted = true;
}
componentWillUnmount() {
this.isMounted = false;
}
仅当this.isMounted为true时,才设置setState。这应该可以解决您的问题,但这不是推荐的模式。请参阅https://reactjs.org/blog/2015/12/16/ismounted-antipattern.html
检查包含<ItemList/>
的父组件的代码。如果您根据某些条件渲染<ItemList/>
,则问题可能出在这些条件下。
答案 1 :(得分:1)
很简单。您只需要在变量中返回第二个Promise的值即可。 像这样:
let items;
let errorFetch;
fetch(url, {mode: 'cors'})
.then(res => res.json())
.then(
(result) => {
items = result;
},
(error) => {
errorFetch = error
}
);
this.setState(items ? { isLoaded : true, items } : { isLoaded : true, error: errorFetch });