React Native API calls return empty array on initial load - need manual save to work

I’m having trouble with fetching data from multiple endpoints in React Native. When I start my app, the console shows an empty array instead of the fetched data. The weird thing is that if I press Ctrl+S to save my file again, then the data appears correctly.

I tried using setInterval to fix this but it just keeps showing empty arrays and doesn’t seem to trigger the fetch requests again.

Here’s my current code:

const [results, setResults] = useState([]);
const itemIds = [10, 20, 30, 40, 50];

useEffect(() => {
  itemIds?.map((itemId) => {
    fetch(`https://jsonplaceholder.typicode.com/posts/${itemId}`)
      .then((res) => res.json())
      .then((item) => setResults((previous) => [...previous, item.title]))
      .catch((err) => console.error(err));
  });
}, []);

console.log(results);

What’s the right way to handle this? I want the data to load properly when the app starts without having to manually save the file. Any suggestions would be really helpful!

you’re console logging before your async operations finish. your useEffect starts the fetches, but console.log runs immediately while the requests are still going. that’s why you see an empty array first. when you hit ctrl+s, the state updates from the previous render are done, so the data shows up. don’t console.log in the render - put it in a separate useEffect that watches for changes to results instead.

You’ve got a race condition problem. Your fetch calls are firing off simultaneously and updating state multiple times, which creates unpredictable behavior. Don’t map over itemIds and call setResults repeatedly. Instead, wait for all promises to finish, then update state once with Promise.all():

useEffect(() => {
  const fetchData = async () => {
    try {
      const promises = itemIds.map(itemId => 
        fetch(`https://jsonplaceholder.typicode.com/posts/${itemId}`)
          .then(res => res.json())
      );
      const items = await Promise.all(promises);
      setResults(items.map(item => item.title));
    } catch (err) {
      console.error(err);
    }
  };
  
  fetchData();
}, []);

This waits for all API calls to complete before updating state, which fixes those timing issues on initial load.

You’re hitting multiple setState calls that fire asynchronously without syncing up. Each fetch finishes at different times and tries updating your results array separately, which messes up state during that first render.

Your map() approach doesn’t wait for requests to finish before the component renders initially. When you save the file, React’s hot reload kicks in after those async operations finally complete - that’s why it works then.

Try using a loading state to handle this properly:

const [results, setResults] = useState([]);
const [loading, setLoading] = useState(true);

useEffect(() => {
  const fetchAllData = () => {
    const requests = itemIds.map(async (itemId) => {
      const response = await fetch(`https://jsonplaceholder.typicode.com/posts/${itemId}`);
      const data = await response.json();
      return data.title;
    });
    
    Promise.all(requests)
      .then(titles => {
        setResults(titles);
        setLoading(false);
      })
      .catch(err => console.error(err));
  };
  
  fetchAllData();
}, []);

This waits for all data before updating state and gives users a better experience with proper loading states.