React Interview Reference

Back to home

Async/Await in React

Using async/await for cleaner asynchronous code in React

Basic Async/Await

Using async/await with event handlers for cleaner code.

jsx
import { useState } from 'react';

function UserForm() {
  const [username, setUsername] = useState('');
  const [status, setStatus] = useState('idle');
  const [userData, setUserData] = useState(null);

  const handleSubmit = async (e) => {
    e.preventDefault();
    setStatus('loading');
    
    try {
      // Fetch user data
      const response = await fetch(`https://api.github.com/users/${username}`);
      
      if (!response.ok) {
        throw new Error('User not found');
      }
      
      const data = await response.json();
      setUserData(data);
      setStatus('success');
    } catch (error) {
      console.error('Error fetching user:', error);
      setStatus('error');
    }
  };

  return (
    <div>
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          value={username}
          onChange={(e) => setUsername(e.target.value)}
          placeholder="GitHub username"
          required
        />
        <button type="submit" disabled={status === 'loading'}>
          {status === 'loading' ? 'Searching...' : 'Search'}
        </button>
      </form>
      
      {status === 'error' && <p>Error: User not found</p>}
      
      {status === 'success' && userData && (
        <div>
          <h2>{userData.name}</h2>
          <p>Followers: {userData.followers}</p>
          <p>Public repos: {userData.public_repos}</p>
        </div>
      )}
    </div>
  );
}

Async/Await in useEffect

Using async/await inside useEffect for data fetching.

jsx
import { useState, useEffect } from 'react';

function ProductList({ categoryId }) {
  const [items, setItems] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    // Create an async function inside useEffect
    const fetchProducts = async () => {
      try {
        setLoading(true);
        const response = await fetch(
          `https://api.example.com/products?category=${categoryId}`
        );
        
        if (!response.ok) {
          throw new Error('Failed to fetch products');
        }
        
        const data = await response.json();
        setItems(data);
        setError(null);
      } catch (error) {
        setError(error.message);
        setItems([]);
      } finally {
        setLoading(false);
      }
    };

    // Call the async function
    fetchProducts();
    
    // Optional: cleanup function
    return () => {
      // Cancel any pending requests if needed
    };
  }, [categoryId]); // Re-run when categoryId changes

  if (loading) return <div>Loading products...</div>;
  if (error) return <div>Error: {error}</div>;
  if (items.length === 0) return <div>No products found</div>;

  return (
    <div>
      <h2>Products in category {categoryId}</h2>
      <ul>
        {items.map((item) => (
          <li key={item.id}>{item.name} - ${item.price}</li>
        ))}
      </ul>
    </div>
  );
}

Parallel Requests

Making multiple API requests in parallel for better performance.

jsx
import { useState, useEffect } from 'react';

function Dashboard() {
  const [userData, setUserData] = useState(null);
  const [postsData, setPostsData] = useState([]);
  const [commentsData, setCommentsData] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchDashboardData = async () => {
      try {
        setLoading(true);
        
        // Make all requests in parallel with Promise.all
        const [userResponse, postsResponse, commentsResponse] = await Promise.all([
          fetch('https://api.example.com/user'),
          fetch('https://api.example.com/posts'),
          fetch('https://api.example.com/comments')
        ]);
        
        // Check if any request failed
        if (!userResponse.ok || !postsResponse.ok || !commentsResponse.ok) {
          throw new Error('One or more requests failed');
        }
        
        // Parse all responses in parallel
        const [user, posts, comments] = await Promise.all([
          userResponse.json(),
          postsResponse.json(),
          commentsResponse.json()
        ]);
        
        // Update state with all data
        setUserData(user);
        setPostsData(posts);
        setCommentsData(comments);
        setError(null);
      } catch (error) {
        setError(error.message);
      } finally {
        setLoading(false);
      }
    };

    fetchDashboardData();
  }, []);

  if (loading) return <div>Loading dashboard data...</div>;
  if (error) return <div>Error: {error}</div>;

  return (
    <div>
      <h1>Dashboard</h1>
      {userData && (
        <div>
          <h2>Welcome, {userData.name}</h2>
        </div>
      )}
      <div>
        <h3>Recent Posts ({postsData.length})</h3>
        <ul>
          {postsData.slice(0, 5).map(post => (
            <li key={post.id}>{post.title}</li>
          ))}
        </ul>
      </div>
      <div>
        <h3>Recent Comments ({commentsData.length})</h3>
        <ul>
          {commentsData.slice(0, 5).map(comment => (
            <li key={comment.id}>{comment.text}</li>
          ))}
        </ul>
      </div>
    </div>
  );
}

Error Handling

Proper error handling with async/await for robust applications.

jsx
import { useState } from 'react';

function PaymentForm() {
  const [cardNumber, setCardNumber] = useState('');
  const [status, setStatus] = useState('idle');
  const [errorMessage, setErrorMessage] = useState('');

  const processPayment = async (paymentDetails) => {
    const response = await fetch('https://api.example.com/payments', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(paymentDetails),
    });
    
    if (!response.ok) {
      // Handle different error status codes
      if (response.status === 400) {
        const errorData = await response.json();
        throw new Error(errorData.message || 'Invalid payment details');
      } else if (response.status === 401) {
        throw new Error('Unauthorized. Please log in again.');
      } else if (response.status === 429) {
        throw new Error('Too many requests. Please try again later.');
      } else {
        throw new Error('Payment processing failed');
      }
    }
    
    return response.json();
  };

  const handleSubmit = async (e) => {
    e.preventDefault();
    setStatus('processing');
    setErrorMessage('');
    
    try {
      // Validate input
      if (cardNumber.length < 16) {
        throw new Error('Invalid card number');
      }
      
      // Process payment
      const result = await processPayment({ cardNumber });
      setStatus('success');
      console.log('Payment successful:', result);
    } catch (error) {
      console.error('Payment error:', error);
      setStatus('error');
      setErrorMessage(error.message);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label htmlFor="card-number">Card Number:</label>
        <input
          id="card-number"
          type="text"
          value={cardNumber}
          onChange={(e) => setCardNumber(e.target.value)}
          placeholder="1234 5678 9012 3456"
        />
      </div>
      
      {status === 'error' && (
        <div style={{ color: 'red' }}>{errorMessage}</div>
      )}
      
      <button 
        type="submit" 
        disabled={status === 'processing'}
      >
        {status === 'processing' ? 'Processing...' : 'Pay Now'}
      </button>
      
      {status === 'success' && (
        <div style={{ color: 'green' }}>Payment successful!</div>
      )}
    </form>
  );
}

Common Interview Questions

  • ?
    What are the advantages of async/await over promises?
  • ?
    How do you handle errors with async/await?
  • ?
    How can you make multiple API calls in parallel with async/await?
  • ?
    What is the relationship between async/await and promises?
  • ?
    How do you use async/await with useEffect?