reactjs - React 如何从 api 获取大量数据
问题描述
我有一个 api,它为我提供了一些我想以最流畅的方式显示到屏幕上的数据。我的想法是以异步方式从 api 获取数据,并在收到来自 api 的响应后立即渲染它。这是我现在的课
import React, { Component, Fragment } from "react";
import Grid from "@material-ui/core/Grid";
import Typography from "@material-ui/core/Typography";
import Episode from "../components/Episode";
import PropTypes from "prop-types";
import { withStyles } from "@material-ui/core/styles";
import CircularProgress from "@material-ui/core/CircularProgress";
const styles = theme => ({
progress: {
display: "flex",
justifyContent: "center",
alignItems: "center"
},
text: {
marginTop: 20,
marginLeft: 30
}
});
class SeriesPage extends Component {
constructor(props) {
super(props);
this.state = {
apiToken: "",
serie: null,
episode: 1,
episodes: [],
endEpisode: 100
};
}
async componentDidMount() {
await this.getTokenFromApi();
await this.getSerieDetailsByApiName();
for(int i = 0; i< this.state.endEpisode; i++){
this.getSerieEpisode();
}
}
getTokenFromApi = async () => {
const data = {
name: "generateToken",
param: {
email: "-",
pass: "-"
}
};
return fetch("api", {
method: "post",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify(data)
})
.then(response => {
if (!response.ok) {
this.setState({
episodes: "Network request failed"
});
throw Error("Network request failed");
}
return response;
})
.then(res => {
return res.json();
})
.then(content => {
if (content.response.status === 200) {
this.setState({
apiToken: content.response.result.token
});
}
})
.catch(error => {
this.setState({
episodes: "There was an internal error"
});
throw error;
});
};
getSerieDetailsByApiName = async () => {
const data = {
name: "getSerieDetailsByApiName",
param: {
serieApiName: this.props.match.params.series
}
};
return fetch("api", {
method: "post",
headers: {
Authorization: "Bearer " + this.state.apiToken,
"Content-Type": "application/json"
},
body: JSON.stringify(data)
})
.then(response => {
if (!response.ok) {
this.setState({
episodes: "Network request failed"
});
throw Error("Network request failed");
}
return response;
})
.then(response => {
return response.json(); //response.json() is resolving its promise. It waits for the body to load
})
.then(responseData => {
if (responseData.response.status === 200) {
this.setState({
serie: responseData.response.result
});
}
})
.catch(error => {
this.setState({
episodes: "There was an internal error"
});
throw error;
});
};
getSerieEpisode = async () => {
const data = {
name: "getEpisodeBySeriesApiName",
param: {
serieApiName: this.props.match.params.series,
ep: this.state.episode
}
};
console.log(data);
return fetch("api", {
method: "post",
headers: {
Authorization: "Bearer " + this.state.apiToken,
"Content-Type": "application/json"
},
body: JSON.stringify(data)
})
.then(response => {
if (!response.ok) {
this.setState({
episodes: "Network request failed"
});
throw Error("Network request failed");
}
return response;
})
.then(response => {
return response.json(); //response.json() is resolving its promise. It waits for the body to load
})
.then(responseData => {
console.log(responseData);
if (responseData.response.status === 200) {
this.setState(prevState => ({
episodes: [...prevState.episodes, responseData.response.result]
}));
}
})
.catch(error => {
this.setState({
episodes: "There was an internal error"
});
});
};
render() {
const { classes, theme } = this.props;
var series =
this.state.serie === "No results found" ? (
<Typography
className={classes.text}
component="h2"
variant="h5"
color="error"
gutterBottom
>
{this.state.serie}
</Typography>
) : this.state.episodes === "There was an internal error" ? (
<Typography
className={classes.text}
component="h2"
variant="h5"
color="error"
gutterBottom
>
{this.state.episodes}
</Typography>
) : (
this.state.episodes.map((item, i) => {
const { classes, headerIsHidden, ...other } = this.props;
return <Episode key={i} episode={item} {...other} />;
})
);
if (this.state.episodes) {
return (
<Fragment>
<div className="series">
<div className="container">
<Grid container spacing={24}>
{series}
{this.state.loadingState ? (
<p className="loading"> loading More Items..</p>
) : (
""
)}
</Grid>
</div>
</div>
</Fragment>
);
} else {
return (
<Grid className={classes.progress} item xs={12}>
<CircularProgress size={100} />
</Grid>
);
}
}
}
export default withStyles(styles, { withTheme: true })(SeriesPage);
基本上,这个类在 componentDidMount 方法上获取数据并为每一集启动一个 for 循环,直到它到达结尾,我觉得这不是更好的方法。有什么提示吗?
解决方案
这种方法的问题是 componentDidMount 和 render 可能需要一段时间才能执行,具体取决于情节的数量。
在我看来,以更流畅的方式做到这一点的方法是:1)使用虚拟化来渲染剧集数据。所以如果你有大量记录,只有可见的才能渲染。看看这个库 https ://github.com/bvaughn/react-virtualized
2)使用按需方法仅获取用户可以看到的数据。您可以通过分页数据来实现这一点,以便用户滚动浏览记录时获取新页面。
推荐阅读
- angular - TestBed 上的提供者和声明有什么区别
- osmnx - OSMnx的道路容量
- python - 在 Python 中的数据框中的列中添加 1 小时
- javascript - 将 ViewModel 从控制器传回 Javascript Function MVC
- c - C、创建具有相同父级的多个进程
- batch-file - 以任何特定模式从最新文件夹中复制 pdf 文件
- java - android:getDeviceList() 总是返回 null
- javascript - JavaScript:无法将第二个值添加到单链表
- spring - Spring框架的事务实现在哪里?
- c++ - 如何使 C++ 中的神经网络实现高效?