All answers

React Native

How do I fix "TypeError: e.map is not a function" in React Native?

The value you're calling .map() on isn't an array. It might be an object that wraps the list, an error response, or a promise you didn't await, and logging it right before the crash shows which. Once you know, read the array from the right key and start your state as an empty array, so the screen can render before the data arrives.

Updated October 31, 2026

TypeError: e.map is not a function makes it sound like .map() itself is broken, and the e doesn’t help. Nothing’s wrong with .map(), though. The e is just a variable name that was shortened when the code was minified for production. What the error means is that the value in front of .map isn’t an array, which you can check in a minute by logging it.

Why it happens

Only arrays have a .map() method, so calling it on an object, a string, or a promise fails with this error. (If the value is undefined or null, you get a related error about reading the property map of undefined instead, and the fix is the same.) When the value comes from an API or from storage, it’s easy to end up with something that looks like a list but isn’t one:

  • The list is wrapped in an object, such as { "results": [...] }. Supabase queries also resolve to an object, { data, error }, with the rows in data.
  • The request failed, and the body is an error object like { "message": "Unauthorized" }.
  • The value is a promise, because an await is missing before an async call.
  • The value is text. Values saved in AsyncStorage come back as strings, so a list you saved there needs JSON.parse before you can map it.
  • The state starts as an object, as in useState({}).

How to fix it

  1. Log what you actually have, right before the line that crashes:

    console.log(typeof items, Array.isArray(items), JSON.stringify(items)?.slice(0, 300));

    In development, the error also names your real variable, like items.map is not a function.

  2. Start the state as an empty array, so the first render has something to map over while the data loads:

    const [items, setItems] = useState<Item[]>([]);
  3. Check the response, then read the list from the right key:

    useEffect(() => {
      async function load() {
        const res = await fetch("https://api.example.com/items");
        if (!res.ok) throw new Error(`Request failed with ${res.status}`);
        const json = await res.json();
        setItems(Array.isArray(json.results) ? json.results : []);
      }
      load().catch(console.warn);
    }, []);

    With Supabase, check the error and fall back to an empty array:

    const { data, error } = await supabase.from("items").select();
    if (error) throw error;
    setItems(data ?? []);
  4. Keep the guard where the data comes in, like the Array.isArray check above. We’d put it there rather than around each .map, so the rest of the screen can trust that items is always an array.

How you know it’s fixed

The screen opens with an empty list, then fills in when the data arrives. With Wi-Fi turned off, a reload shows an empty or error state instead of a red error screen.

If it still fails

If the log shows an object whose keys are IDs, like { "a1": {...}, "b2": {...} }, it’s a collection stored as an object, and Object.values(items) turns it into an array you can map. If the log shows a string that starts with [, parse it with JSON.parse before you store it. And if the log shows {} for something you expected to be a list, look for a missing await where the value was set.

Ask the agent

If your app is in Draftbit, paste this into the agent, and it can read your code and make the change for you.

My screen crashes with "e.map is not a function". Find the list it's mapping over, log what the API actually returns, read the array from the right field, start the state as an empty array, and show an empty or error state when the request fails.

Open Draftbit

More React Native answers