简体   繁体   中英

TypeError: data.map is not a function in reactjs while loading photos

I've tried to create an image search application using unsplash api but it shows the error TypeError: data.map is not a function . It was working fine till last night but now it suddenly shows this error. It initially loaded the page with the images but it started showing this error when I searched for moon and went to last page. I then refreshed the page and it displays the images again but as soon as I did per_page items from 5 to 9 then it shows the error again and now it''s continously showing the error. Is it a problem with the api? but even if it was the api, it should show a blank page because I did photos: [] in the try catch block in the api call method but instead it shows the error. I'm not sure what is wrong with my code. Can someone help me please

App.js

import React, { Component } from "react";
import Pagination from "./Pagination";
import List from "./List";
import "./styles.css";
import axios from "axios";

const LOAD_STATE = {
  SUCCESS: "SUCCESS",
  ERROR: "ERROR",
  LOADING: "LOADING"
};

const appId = "N1ZIgf1m1v9gZJhledpAOTXqS8HqL2DuiEyXZI9Uhsk";

export default class App extends Component {
  constructor() {
    super();
    this.handleChange = this.handleChange.bind(this);
    this.fetchPhotos = this.fetchPhotos.bind(this);
    this.state = {
      photos: [],
      totalPhotos: 0,
      perPage: 5,
      currentPage: 1,
      loadState: LOAD_STATE.LOADING,
      search: ""
    };
  }
  handleChange(e) {
    this.setState({ search: e.target.value });
  }

  componentDidMount() {
    this.fetchPhotos(this.state.currentPage);
  }

  fetchPhotos(page = 1) {
    var self = this;
    const { search, perPage } = this.state;
    const url1 = `https://api.unsplash.com/photos?page=${page}&client_id=${appId}`;
    const url2 =
      `https://api.unsplash.com/search/photos?page=${page}&query=` +
      search +
      "&client_id=" +
      appId;
    const url = search ? url2 : url1;

    if (search) {
      const options = {
        params: {
          page: page,
          per_page: perPage,
          order_by: "popularity"
        }
      };

      this.setState({ loadState: LOAD_STATE.LOADING });
      axios
        .get(url, options)
        .then(response => {
          console.log(typeof response.data);
          let photos;
          try {
            photos = response.data.results;
          } catch {
            photos = [];
          }
          this.setState({
            photos,
            totalPhotos: parseInt(response.headers["x-total"]),
            currentPage: page,
            loadState: LOAD_STATE.SUCCESS
          });
        })
        .catch(() => {
          this.setState({ loadState: LOAD_STATE.ERROR });
        });
    } else {
      const options = {
        params: {
          client_id: appId,
          page: page,
          per_page: perPage,
          order_by: "popularity"
        }
      };

      this.setState({ loadState: LOAD_STATE.LOADING });
      axios
        .get(url, options)
        .then(response => {
          console.log(typeof response.data);
          let photos;
          try {
            photos = response.data;
          } catch {
            photos = [];
          }
          self.setState({
            photos,
            totalPhotos: parseInt(response.headers["x-total"]),
            currentPage: page,
            loadState: LOAD_STATE.SUCCESS
          });
        })
        .catch(() => {
          this.setState({ loadState: LOAD_STATE.ERROR });
        });
    }
  }

  render() {
    return (
      <div className="app">
        <input
          onChange={this.handleChange}
          type="text"
          name="search"
          placeholder="Enter query"
        />
        <button
          type="submit"
          onClick={() => this.fetchPhotos(1)}
          className="button"
        >
          Submit
        </button>
        <Pagination
          current={this.state.currentPage}
          total={this.state.totalPhotos}
          perPage={this.state.perPage}
          onPageChanged={this.fetchPhotos.bind(this)}
        />
        {this.state.loadState === LOAD_STATE.LOADING ? (
          <div className="loader" />
        ) : (
          <List data={this.state.photos} />
        )}
        <Pagination
          current={this.state.currentPage}
          total={this.state.totalPhotos}
          perPage={this.state.perPage}
          onPageChanged={this.fetchPhotos.bind(this)}
        />
      </div>
    );
  }
}

List.js

import React from "react";
import ListItem from "./ListItem";
const List = ({ data }) => {
  var items = data.map(photo => <ListItem key={photo.id} photo={photo} />); //error here
  return <div className="grid">{items}</div>;
};

export default List;

I found out the problem that you are facing, the issue is when there is empty data from the API response the photos variable stays like photos = {} where in expected is photos = [] , which you did in catch block but it never goes to catch block because having empty data is not error, also I have solved your issue here Demo .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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