Реагируйте, как получить много данных из API - PullRequest
0 голосов
/ 22 октября 2018

У меня есть 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 для каждого эпизода, пока он не достигнет конца, я чувствую, что это не лучший способ.Любые советы?

Ответы [ 2 ]

0 голосов
/ 23 октября 2018

Вы можете использовать redux-saga, он предоставляет простые в использовании встроенные функции, такие как «fork», которые ведут себя как слушатель и запускают процесс выборки в фоновом режиме.Другие функции или, как они это называют, «эффекты» также доступны.Они действительно просты в использовании и идеально подходят для вашего случая использования. Пример вилки

0 голосов
/ 22 октября 2018

Проблема с этим подходом состоит в том, что componentDidMount и рендеринг могут выполняться некоторое время в зависимости от количества эпизодов.

Способ сделать это более плавным способом, возможным, на мой взгляд, состоит в следующем: 1) Используйте виртуализацию для рендеринга данных эпизода. Так что, если у вас есть большое количество записей, только то, что видимо, получите render. Посмотрите на эту библиотеку https://github.com/bvaughn/react-virtualized

2) Используйте подход по требованию, чтобы только выбиратьданные, которые может видеть пользователь. Вы можете достичь этого, разбивая страницы на страницы, чтобы пользователь просматривал записи, выбирая новые страницы.

...