ReactJS中如何通过搜索框关键词从多URL用Promise获取JSON数据?
Hey there! Great question—handling multiple API requests efficiently while passing search params is a common scenario, and Promises are perfect for this. Let's break down how to do this cleanly, with some optimizations to make it even better.
1. First, Build a Reusable Fetch Utility
Instead of repeating fetch logic for each API, create a helper function that handles URL construction, search params, and error handling in one place. This keeps your code DRY and easier to maintain:
const fetchWithSearchParams = async (baseUrl, params) => { const url = new URL(baseUrl); // Add all search params to the URL Object.entries(params).forEach(([key, value]) => { url.searchParams.append(key, value); }); try { const response = await fetch(url); if (!response.ok) { throw new Error(`Request failed with status: ${response.status}`); } return await response.json(); } catch (err) { console.error(`Failed to fetch ${baseUrl}:`, err); throw err; // Let the caller handle the error if needed } };
This function takes your base API URL and a params object (like { search: "your-term" }), builds the full URL with query strings, and returns the parsed JSON response.
2. Fetch All APIs in Parallel with Promise.all
Now use this utility to create fetch promises for all your APIs, then run them in parallel with Promise.all—this is way more efficient than running them sequentially:
const fetchAllDatasets = async (searchTerm) => { const apiEndpoints = [ 'localhost:3000/api/getdata1', 'localhost:3000/api/getdata2', 'localhost:3000/api/getdata3' ]; // Create a promise for each API, passing the search term as a param const fetchPromises = apiEndpoints.map(endpoint => fetchWithSearchParams(endpoint, { search: searchTerm }) // Replace "search" with your actual query param key if it's different ); try { // Wait for all promises to resolve const allResults = await Promise.all(fetchPromises); // allResults will be an array where index 0 = getdata1, index1 = getdata2, etc. return allResults; } catch (err) { console.error('One or more API requests failed:', err); // Handle the error here (e.g., show a user-friendly message) } };
To connect this to your search box, add an event listener that triggers the fetch when the user types:
// Assuming your search input has an id of "searchInput" const searchInput = document.getElementById('searchInput'); searchInput.addEventListener('input', async (e) => { const term = e.target.value.trim(); if (term) { const data = await fetchAllDatasets(term); // Pass the data to your frontend rendering function renderDataToUI(data); } else { // Clear the UI if the search term is empty clearUI(); } });
3. Optimize for Efficiency
If you want to make this even more efficient, add these tweaks:
Debounce the Search Input
Prevent unnecessary API calls when the user types quickly by adding a debounce—this waits until the user stops typing for a set time (e.g., 300ms) before sending the request:
const debounce = (func, delay) => { let timeoutId; return (...args) => { clearTimeout(timeoutId); timeoutId = setTimeout(() => func.apply(this, args), delay); }; }; // Wrap your fetch call with debounce const debouncedFetch = debounce(async (term) => { if (term) { const data = await fetchAllDatasets(term); renderDataToUI(data); } else { clearUI(); } }, 300); // Update the event listener to use the debounced function searchInput.addEventListener('input', (e) => { debouncedFetch(e.target.value.trim()); });
Cache Results
Avoid re-fetching data for the same search term by adding a cache. This saves bandwidth and makes your app feel faster:
const searchCache = new Map(); const fetchAllDatasets = async (searchTerm) => { // Check cache first if (searchCache.has(searchTerm)) { console.log('Using cached data for:', searchTerm); return searchCache.get(searchTerm); } const apiEndpoints = [ 'localhost:3000/api/getdata1', 'localhost:3000/api/getdata2', 'localhost:3000/api/getdata3' ]; const fetchPromises = apiEndpoints.map(endpoint => fetchWithSearchParams(endpoint, { search: searchTerm }) ); try { const allResults = await Promise.all(fetchPromises); // Store in cache, with an optional expiration (e.g., 5 minutes) searchCache.set(searchTerm, allResults); setTimeout(() => searchCache.delete(searchTerm), 5 * 60 * 1000); return allResults; } catch (err) { console.error('Request failed:', err); throw err; } };
Handle Partial Failures (Optional)
If you want to display successful results even if one API fails, use Promise.allSettled instead of Promise.all. This returns an array of objects showing which requests succeeded or failed:
const fetchAllDatasets = async (searchTerm) => { const apiEndpoints = [ 'localhost:3000/api/getdata1', 'localhost:3000/api/getdata2', 'localhost:3000/api/getdata3' ]; const fetchPromises = apiEndpoints.map(endpoint => fetchWithSearchParams(endpoint, { search: searchTerm }) ); const results = await Promise.allSettled(fetchPromises); // Process results to separate success/failure const processedResults = results.map((result, index) => ({ endpoint: apiEndpoints[index], success: result.status === 'fulfilled', data: result.status === 'fulfilled' ? result.value : null, error: result.status === 'rejected' ? result.reason : null })); return processedResults; };
Then in your UI, you can render the successful data and show errors for the failed ones.
内容的提问来源于stack exchange,提问作者stone rock

