You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React渲染Unsplash搜索图片时遇image.map is not a function错误

Fixing the image.map is not a function Error & Implementing Unsplash Image Search in React

Hey there! Let's break down what's going wrong and get your image search feature working smoothly.

Why You're Seeing That Error

The core issue here is that the data you're storing in your image state isn't an array—it's an object. When you call Unsplash's /search/photos API, the response structure looks like this:

{
  "results": [...], // This is the actual array of images you need
  "total": 123,
  "total_pages": 6
}

Right now, you're setting image to data.data (the entire response object), which doesn't have a map method. That's why you're getting the error!

Step-by-Step Fix & Full Implementation

1. Correctly Extract the Image Array from the API Response

Update your fetchImages function to grab the results array from the API response instead of the whole object. Also, fix the Authorization header format—Unsplash requires it to be Client-ID YOUR_ACCESS_KEY:

const fetchImages = () => {
  // Don't make a request if the search input is empty
  if (!searchText.trim()) {
    setImage([]);
    return;
  }

  setIsLoading(true);
  axios.get('https://api.unsplash.com/search/photos', {
    params: { query: searchText },
    headers: { Authorization: `Client-ID ${API_KEY}` }, // Fixed auth format
  })
  .then((response) => {
    // Store the actual image array (response.data.results)
    setImage(response.data.results);
  })
  .catch((err) => {
    console.error('Failed to load images:', err);
    setImage([]); // Reset to empty array on error to avoid future issues
  })
  .finally(() => {
    setIsLoading(false);
  });
};

2. Clean Up the ImageList Component

Add a default empty array to the image prop to avoid null/undefined checks, and add basic styling to make your images look organized:

/* eslint-disable jsx-a11y/alt-text */
/* eslint-disable react/prop-types */
import React from 'react';

const ImageList = ({ image = [] }) => {
  const imgs = image.map(img => (
    <img 
      key={img.id} 
      src={img.urls.regular} 
      style={{ width: '100%', height: '200px', objectFit: 'cover', borderRadius: '8px' }}
    />
  ));

  return (
    <div style={{ 
      display: 'grid', 
      gridTemplateColumns: 'repeat(auto-fill, minmax(250px, 1fr))', 
      gap: '15px',
      marginTop: '20px'
    }}> 
      {imgs} 
    </div>
  );
};

export default ImageList;

3. Add Quality-of-Life Improvements (Optional)

  • Loading State: Let users know when images are being fetched by adding an isLoading state:

    // Add this state to your SearchPage component
    const [isLoading, setIsLoading] = useState(false);
    

    Then render a loading message in your JSX:

    {isLoading && <p style={{ textAlign: 'center', fontSize: '1.2rem' }}>Loading images...</p>}
    
  • Debounced Search: Prevent excessive API calls by adding a delay before fetching images as the user types. You can use Lodash's debounce or implement your own:

    import { useCallback } from 'react';
    import { debounce } from 'lodash';
    
    // Inside your SearchPage component
    const debouncedFetch = useCallback(debounce((query) => {
      if (query.trim()) {
        // Reuse your fetch logic here, or adjust fetchImages to accept a query parameter
        axios.get('https://api.unsplash.com/search/photos', {
          params: { query },
          headers: { Authorization: `Client-ID ${API_KEY}` },
        })
        .then(res => setImage(res.data.results))
        .catch(err => console.error(err));
      } else {
        setImage([]);
      }
    }, 500), []);
    
    // Update onInputChange to use the debounced function
    const onInputChange = (e) => {
      const value = e.target.value;
      setSearchTerm(value);
      debouncedFetch(value);
    };
    

Full Updated SearchPage Component

import React, { useState } from 'react';
import axios from 'axios';
import SearchBar from '../SearchBar/SearchBar';
import ImageList from '../ImageList/ImageList';

const API_KEY = process.env.REACT_APP_ACCESS_KEY;

const SearchPage = () => {
  const [searchText, setSearchTerm] = useState('');
  const [image, setImage] = useState([]);
  const [isLoading, setIsLoading] = useState(false);

  const onInputChange = (e) => {
    setSearchTerm(e.target.value);
  };

  const fetchImages = () => {
    if (!searchText.trim()) {
      setImage([]);
      return;
    }
    setIsLoading(true);
    axios.get('https://api.unsplash.com/search/photos', {
      params: { query: searchText },
      headers: { Authorization: `Client-ID ${API_KEY}` },
    })
    .then((response) => {
      setImage(response.data.results);
    })
    .catch((err) => {
      console.error('Failed to load images:', err);
      setImage([]);
    })
    .finally(() => {
      setIsLoading(false);
    });
  };

  const onSubmitHandler = (e) => {
    e.preventDefault();
    fetchImages();
  };

  return (
    <div style={{ maxWidth: 1200, margin: '0 auto', padding: '20px' }}>
      <SearchBar 
        onSubmitHandler={onSubmitHandler} 
        onInputChange={onInputChange} 
        searchText={searchText} 
      />
      {isLoading && <p style={{ textAlign: 'center', fontSize: '1.2rem' }}>Loading images...</p>}
      <ImageList image={image} />
    </div>
  );
};

export default SearchPage;

That's it! This fixes the map error, implements the search functionality correctly, and adds some nice touches to improve the user experience.

内容的提问来源于stack exchange,提问作者SImon Haddad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 06:42:57