skip to Main Content

I’m trying to fetch city data using the OpenCage API and display the results in a list using React and Chakra UI. However, I’m getting the following error: Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object. I use page routing. This is my code:

import NextLink from "next/link";
import { useState } from "react";

export default function Search() {
  const [searchTerm, setSearchTerm] = useState("");
  const [results, setResults] = useState([]);

  const handleSearch = async () => {
    if (!searchTerm.trim()) return;

    const response = await fetch(
      `https://api.opencagedata.com/geocode/v1/json?q=${searchTerm}&key=YOUR_API_KEY`
    );
    const data = await response.json();

    const cityResults = data.results.map((result) => ({
      id: `${result.geometry.lat},${result.geometry.lng}`,
      name: result.formatted,
      lat: result.geometry.lat,
      lng: result.geometry.lng,
    }));

    setResults(cityResults);
  };

  return (
    <Box>
      <Text>Search for a city</Text>
      <Input value={searchTerm} onChange={(e) => setSearchTerm(e.target.value)} />
      <Button onClick={handleSearch}>Search</Button>
      <List>
        {results.map((city) => (
          <ListItem key={city.id}>
            <NextLink href={`/city/${city.id}`} passHref>
              <Link>{city.name}</Link>
            </NextLink>
          </ListItem>
        ))}
      </List>
    </Box>
  );
}

When I attempt to render the results, I get the error Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.
I’ve tried using forEach() instead of map(), checked if I’m importing the components correctly, and ensured that the data returned from the API is in the expected format, but the issue persists.
I’ve checked the imports of NextLink, List, and ListItem.
Is working fine showing only one result with the following code:


  const [searchTerm, setSearchTerm] = useState("");
  const [result, setResult] = useState(null); 

 .....

      const firstCity = data.results[0]; // Take only the first result
      const city = {
        id: `${firstCity.geometry.lat},${firstCity.geometry.lng}`,
        name: firstCity.formatted,
        lat: firstCity.geometry.lat,
        lng: firstCity.geometry.lng,
      };

      setResult(city);
      console.log("Result:", city);
    } catch (error) {
      console.error("Error fetching data:", error);
      alert("Something went wrong. Please try again.");
    }
  };

  return (
    <>
     ....
        
          <Box mt={8} px={4}>
        {result ? (
          <Box>
            <Text fontSize="lg">
              <NextLink href={`/city/${result.id}`} passHref>
                <Link color="teal.500">
                  {result.name} (Lat: {result.lat}, Lng: {result.lng})
                </Link>
              </NextLink>
            </Text>
          </Box>
        ) : (
          <Text>No results found</Text>
        )}
      </Box>
    </>
  );
}

Any help is greatly appreciated!

2

Answers


  1. You should always perform a check before rendering:

    <List>
      {results.length > 0 && results.map((city) => (
        <ListItem key={city.id}>
          <NextLink href={`/city/${city.id}`} passHref>
            <Link>{city.name}</Link>
          </NextLink>
        </ListItem>
      ))}
    </List>
    

    This is because, at the moment you try to map over results, your asynchronous fetch might not have returned the data yet.

    I advise implementing a loader or using a Skeleton component to display while results.length is still empty.

    Login or Signup to reply.
  2. Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.
    

    is your indication that one of the element you are trying to render is not a string but an object, the best way to tackle this would be console.log(result) and make sure the output of the result is in a syntax that is compatible of how you are rendering it i.e., {id, name, lat, long} are flat object of result and that there is no further nesting.

    and make sure to validate if the data is available when rendering, else it will fail when there is no data. city?.name.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search