Debouncing is a way to delay a function from executing until a certain amount of time after the last action, when a new action is performed, it resets the countdown.
import React, { useState } from "react";
// Debounce function
const debounce = (fn, delay = 1000) => {
let timerId = null;
return (...args) => {
clearTimeout(timerId);
timerId = setTimeout(() => fn(...args), delay);
};
};
// Example function to be debounced
const makeAPICall = (value) => {
console.log("API call with:", value);
};
const DebouncedInput = () => {
const [inputValue, setInputValue] = useState("");
const handleInput = debounce((value) => {
makeAPICall(value);
}, 500);
const handleKeyUp = (event) => {
const { value } = event.target;
setInputValue(value);
handleInput(value);
};
return (
<div>
<input type="text" value={inputValue} onKeyUp={handleKeyUp} />
</div>
);
};
export default DebouncedInput;
Filtered Items was being displayed on the FE, and failing because it had 6,000 records. The better option is to pass a limit to the API
const filteredItems =
searchValue === ""
? items.slice(0, 50)
: items
.filter((item) => {
return item.name?.toLowerCase().includes(searchValue.toLowerCase());
})
.slice(0, 50);
const [loading, setLoading] = useState(false);
const uploadFiles = async () => {
setLoading(true);
///await call api here
setLoading(false);
};
<Button
variant="primary"
onClick={async () => await uploadFiles()}
disabled={loading}
className="min-w-[12rem]"
>
{loading ? <>Uploading...</> : <>Upload</>}
</Button>;
import Loading from "./loading"
import Photos from "./photos"
const PhotoContainer = () => {
const [isLoading, setIsLoading] = useState(true);
return (
<div>
{isLoading ? (
<Loading />
) : (
<div>
<Photos>
)}
</div>
);
};
import React, { useState, useEffect } from "react";
import {
BrowserRouter as Router,
Route,
useHistory,
useLocation,
} from "react-router-dom";
// Mock function to simulate fetching search results
const fetchResults = async (query) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve([`Result for ${query} 1`, `Result for ${query} 2`]);
}, 1000);
});
};
const Search = () => {
const history = useHistory();
const location = useLocation();
const [query, setQuery] = useState(
new URLSearchParams(location.search).get("query") || ""
);
const [results, setResults] = useState([]);
const [isLoading, setIsLoading] = useState(false);
// Performs search when query params (anything after the ?) change
useEffect(() => {
// locaction.search is react built in for anything after the ? in the url
const params = new URLSearchParams(location.search);
// this gets your actual query, which is set to "query="
const searchQuery = params.get("query");
if (searchQuery) {
performSearch(searchQuery);
}
// update when location.search changes
}, [location.search]);
const performSearch = async (searchQuery) => {
setIsLoading(true);
const fetchedResults = await fetchResults(searchQuery);
setResults(fetchedResults);
setIsLoading(false);
};
const handleSearch = (e) => {
e.preventDefault();
// update the url location on search, which triggers use effect
history.push(`?query=${query}`);
};
return (
<div>
<form onSubmit={handleSearch}>
<input
type="text"
value={query}
onChange={(e) => setQuery(e.target.value)}
/>
<button type="submit">Search</button>
</form>
{isLoading ? (
<p>Loading...</p>
) : (
<ul>
{results.map((result, index) => (
<li key={index}>{result}</li>
))}
</ul>
)}
</div>
);
};
const App = () => (
<Router>
<Route path="/" component={Search} />
</Router>
);
export default App;
Lazyload makes it so if you want to show 50 images at once, it will have the html already, but the images themselves won't load until you scroll down to them. This is an easy way to do pseudo infinite scroll.
(if they ask for ideas on how to make the UI better, or the experience faster, you can mention this as an easy way.)
- Avoid using Divs: Header
- Associate labels and inputs
- Use alt tags for photos
- aria-labelled by is a way to associate labels with any element
<body>
<header>
<h1>Photo Search</h1>
<form role="search">
<label for="search-query">Search Photos</label>
<input type="text" id="search-query" name="query" placeholder="Enter search term" />
<button type="submit">Search</button>
</form>
</header>
<main>
<section aria-labelledby="results-heading">
<h2 id="results-heading">Search Results</h2>
<ul>
<li>
<img src="photo1.jpg" alt="Description of photo 1" />
<p>Photo 1 Description</p>
</li>
<li>
<img src="photo2.jpg" alt="Description of photo 2" />
<p>Photo 2 Description</p>
</li>
<!-- More photo results -->
</ul>
</section>
</main>
<footer>
<p>© 2024 Photo Search. All rights reserved.</p>
</footer>
</body>
</html>