简体   繁体   English

React如何从api获取大量数据

[英]React how to fetch a lot of data from an api

I have an api which provides me with some data which I want to display to the screen int the smoothest way. 我有一个api,可为我提供一些要以最流畅的方式显示在屏幕上的数据。 My idea was to fetch data in an async way from the api and render it as soon I receive a response from the api. 我的想法是从api以异步方式获取数据,并在收到api的响应后立即渲染它。 This is my class right now 这是我班

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);

Basically, this class fetches the data on the componentDidMount method and starts a for loop for every episode, until it reaches the end, I feel like this is not better way.Any tips? 基本上,此类会获取componentDidMount方法上的数据并为每个情节启动一个for循环,直到到达结尾为止,我觉得这不是更好的方法。

The problem with this approach is that componentDidMount and render can take a while to execute depending in the number of episode. 这种方法的问题在于componentDidMount和render可能需要一段时间才能执行,具体取决于情节数。

The way to do this in the smoother way possible in my opinion is to is: 1)Use virtualisation for rendering the episode data.So if you have a large number of records only what is visible get render.Take a look at this library https://github.com/bvaughn/react-virtualized 在我看来,可能平滑的方式来做到这一点的方法是是:1)使用虚拟化渲染情节data.So如果您有大量的记录只有什么是可见得到render.Take看看这个库HTTPS ://github.com/bvaughn/react-virtualized

2)Use an on demand approach to only fetch the data that the user can see.You can achieve this by paging the data, so as the user scroll through the records new pages are fetched. 2)使用按需方式仅获取用户可以看到的数据。您可以通过分页数据来实现此目的,以便在用户滚动记录时获取新页面。

You can use redux-saga, it provides easy to use built in functions like "fork", which behaves as a listener and start the fetching process in the background. 您可以使用redux-saga,它提供了易于使用的内置函数,例如“ fork”,它充当侦听器并在后台启动获取过程。 Other functions or as they call it "effects" are also available. 也可以使用其他功能或称之为“效果”的功能。 They are really easy to use and perfect for your use case. 它们非常易于使用,非常适合您的用例。 Fork example 货叉示例

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM