React Asynchronously with API: Complete Example for a Search Use Case

React Asynchronously with API: Complete Example for a Search Use Case

Building responsive, user-centric search features is essential in modern web applications. React, with its asynchronous capabilities and hooks, provides a robust framework to handle such requirements effectively. This whitepaper demonstrates how to asynchronously interact with an API in React using a search use case as an example.

🔍 Use Case Overview

We aim to create a React component that allows users to type a query into a search input, asynchronously fetch matching results from a public API (we'll use the Open Library API), and display the results in real-time.

🛠️ Tools & Libraries

  • React (v18+)
  • fetch API for network requests
  • useState and useEffect for managing state and side effects

📦 Example Code


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

function BookSearch() {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  useEffect(() => {
    const controller = new AbortController();

    if (query.length < 3) {
      setResults([]);
      return;
    }

    const fetchData = async () => {
      setLoading(true);
      setError(null);

      try {
        const response = await fetch(
          \`https://openlibrary.org/search.json?q=\${encodeURIComponent(query)}\`,
          { signal: controller.signal }
        );

        if (!response.ok) {
          throw new Error('Failed to fetch data');
        }

        const data = await response.json();
        setResults(data.docs.slice(0, 10)); // Limit to top 10 results
      } catch (err) {
        if (err.name !== 'AbortError') {
          setError(err.message);
        }
      } finally {
        setLoading(false);
      }
    };

    const timeoutId = setTimeout(fetchData, 500); // Debounce

    return () => {
      controller.abort();
      clearTimeout(timeoutId);
    };
  }, [query]);

  return (
    <div style={{ padding: '20px', maxWidth: '600px', margin: '0 auto' }}>
      <h2>Book Search</h2>
      <input
        type="text"
        placeholder="Search for books..."
        value={query}
        onChange={(e) => setQuery(e.target.value)}
        style={{ width: '100%', padding: '10px', fontSize: '16px' }}
      />

      {loading && <p>Loading...</p>}
      {error && <p style={{ color: 'red' }}>{error}</p>}

      <ul>
        {results.map((book, index) => (
          <li key={index}>
            <strong>{book.title}</strong> by {book.author_name?.[0] || 'Unknown'}
          </li>
        ))}
      </ul>
    </div>
  );
}

export default BookSearch;

✅ Key Concepts Demonstrated

  • Debouncing: Delays requests to avoid overloading the API with every keystroke.
  • AbortController: Cancels ongoing requests if the query changes quickly.
  • Error Handling: Displays user-friendly error messages.
  • State Management: Manages query, loading, and results effectively with hooks.

🧠 Best Practices

  • Use debounce for search to reduce unnecessary API calls.
  • Always clean up asynchronous effects to avoid memory leaks.
  • Display meaningful loading and error states to users.

📚 Conclusion

This example demonstrates how React’s asynchronous capabilities and lifecycle management can be effectively applied to a real-world search feature. Whether building a book finder, movie explorer, or product catalog, this approach ensures a smooth and efficient user experience.

Happy coding! 🚀

Comments

Popular posts from this blog

About naveen gaayaru

About Naveen G

First React app