在React useEffect中限制搜索结果展示数量的实现方案
Problem Description
I have a React component that fetches 500 country records and filters them based on user search input. Right now, it displays all matching results (or even all 500 when the search box is empty), which isn't practical. I want to modify the code to only show up to 10 results at a time.
Here's my current code:
function App() { const [countries, setCountries] = useState([]); const [loading, setLoading] = useState(false); const [search, setSearch] = useState(""); const [filteredCountries, setFilteredCountries] = useState([]); useEffect(() => { setLoading(true); axios .get("https://www.countriesapi.com") .then((res) => { setCountries(res.data); setLoading(false); }) .catch((err) => { console.log(err); }); }, []); useEffect(() => { setFilteredCountries( countries.filter((country) => country.name.toLowerCase().includes(search.toLowerCase()) ) ); }, [search, countries]); if (loading) { return <p>Loading countries...</p>; } return ( <div className="App"> <h1>Countries Lists</h1> <a style={{ color: "red" }} target="_blank" href="https://www.somesite.com" ></a> <input type="text" placeholder="Search Countries" onChange={(e) => setSearch(e.target.value)} /> {filteredCountries.map((country, idx) => ( <CountryDetail key={idx} {...country} /> ))} </div> ); }
Solution
Great question—displaying 500 results at once is definitely overwhelming for users, especially before they start typing. Here's how you can adjust your code to limit results to 10 and avoid showing all entries when there's no search input:
We need two key adjustments:
- Prevent showing all countries when search is empty: No need to load 500 entries before the user types anything.
- Limit filtered results to 10 entries: Use JavaScript's
slice()method to cap the number of displayed items.
Here's the modified code with comments highlighting changes:
function App() { const [countries, setCountries] = useState([]); const [loading, setLoading] = useState(false); const [search, setSearch] = useState(""); const [filteredCountries, setFilteredCountries] = useState([]); useEffect(() => { setLoading(true); axios .get("https://www.countriesapi.com") .then((res) => { setCountries(res.data); setLoading(false); }) .catch((err) => { console.log(err); }); }, []); useEffect(() => { // Only filter if search input is not empty if (!search.trim()) { setFilteredCountries([]); return; } const filtered = countries.filter((country) => country.name.toLowerCase().includes(search.toLowerCase()) ); // Slice to keep only the first 10 results setFilteredCountries(filtered.slice(0, 10)); }, [search, countries]); if (loading) { return <p>Loading countries...</p>; } return ( <div className="App"> <h1>Countries Lists</h1> <a style={{ color: "red" }} target="_blank" href="https://www.somesite.com" ></a> <input type="text" placeholder="Search Countries" onChange={(e) => setSearch(e.target.value)} /> {/* Optional: Add feedback for no matching results */} {filteredCountries.length === 0 && search.trim() && ( <p>No countries found matching your search.</p> )} {filteredCountries.map((country, idx) => ( <CountryDetail key={idx} {...country} /> ))} </div> ); }
Key Changes Explained
- Empty search handling: When the search input is blank (after trimming whitespace), we set
filteredCountriesto an empty array. This avoids loading all 500 countries before the user starts typing. - Result limiting: After filtering the countries, we use
slice(0, 10)to take only the first 10 matching entries. This ensures the page never displays more than 10 results at once. - User feedback (optional): Added a message to let users know when no results match their search query, which improves overall user experience.
You could also slice the results directly in the render method (e.g., filteredCountries.slice(0,10).map(...)), but handling it in the useEffect is more efficient since it only runs when search or countries changes, rather than on every render.
内容的提问来源于stack exchange,提问作者RandomDeveloper

