How to use async/await in React data fetching
Using async/await syntax makes data fetching code more readable and easier to debug compared to promise chains, especially when handling multiple sequential API calls. As the creator of CoreUI, a widely used open-source UI library, I’ve implemented async/await patterns in React components across numerous projects over 25 years of development. From my expertise, the most effective approach is creating async functions within useEffect using immediately invoked function expressions (IIFE). This provides clean, synchronous-looking code while maintaining proper React lifecycle management.
Use async/await within useEffect by creating an immediately invoked async function.
const [data, setData] = useState(null)
useEffect(() => {
  (async () => {
    try {
      const response = await fetch('/api/users')
      const result = await response.json()
      setData(result)
    } catch (error) {
      console.error('Error fetching data:', error)
    }
  })()
}, [])
Here the async function is immediately invoked within useEffect since useEffect cannot be async itself. The try/catch block handles errors synchronously, making error handling more intuitive. The await keywords make the code read like synchronous operations while maintaining the asynchronous nature of HTTP requests.
Best Practice Note:
This is the same async pattern we use in CoreUI React components for complex data operations. Always wrap async operations in try/catch blocks and consider extracting complex async logic into custom hooks for better reusability and testing.



