Skip to content

Instantly share code, notes, and snippets.

@rafaelcamargo
Last active March 13, 2023 09:34
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rafaelcamargo/eda94014a8e087334a201feea1f6e6df to your computer and use it in GitHub Desktop.
Save rafaelcamargo/eda94014a8e087334a201feea1f6e6df to your computer and use it in GitHub Desktop.
React Query Debounce
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=5">
<title>Debounce</title>
<style media="screen">
html, body {
margin: 0;
font-family: Arial, sans-serif;
}
.app {
margin: 0 auto;
padding: 0 0 50px;
width: 90%;
max-width: 400px;
}
.loader {
margin-top: 50px;
text-align: center;
}
.bar {
position: sticky;
padding: 25px 0;
top: 0;
background-color: rgba(255, 255, 255, 0.85);
backdrop-filter: blur(12px);
}
input {
padding: 10px;
width: 100%;
font-size: 16px;
border: 1px solid #c6c6c6;
border-radius: 4px;
box-sizing: border-box;
-webkit-appearance: none;
}
ul {
margin: 30px 0 0;
padding: 0;
list-style-type: none;
}
li {
display: inline-block;
width: 100%;
text-transform: capitalize;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
li:not(:first-child) {
margin-top: 10px;
padding-top: 10px;
border-top: 1px solid #c6c6c6;
}
</style>
</head>
<body>
<div data-root class="app"><div class="loader">Loading...</div></div>
<script src="https://cdn.jsdelivr.net/npm/react@16.14.0/umd/react.production.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/react-dom@16.14.0/umd/react-dom.production.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@babel/standalone@7.13.8/babel.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/react-query@3.39.3/dist/react-query.production.min.js"></script>
<script type="text/babel">
(function(){
const { useState, useEffect } = React;
// React Query Global Setup
const { QueryClient, QueryClientProvider } = ReactQuery;
const queryClient = new QueryClient({
defaultOptions: { queries: { refetchOnWindowFocus: false } }
});
// Query Debounce
const useCustomQuery = (params, request, { debounce, ...options } = {}) => {
const [newParams, setNewParams] = useState(params);
const stringify = obj => JSON.stringify(obj);
useEffect(() => {
if (stringify(params) !== stringify(newParams)) {
const timerId = setTimeout(() => setNewParams(params), debounce);
return () => clearTimeout(timerId);
}
}, [params]);
return ReactQuery.useQuery(newParams, request, options);
}
const App = () => {
const [term, setTerm] = useState('');
const handleTermChange = term => typeof term == 'string' && setTerm(term);
const { data: posts } = useCustomQuery(
['posts', term],
() => fetch(
`https://jsonplaceholder.typicode.com/posts?q=${term}&_limit=20`
).then(response => response.json()),
{ debounce: 750 }
);
return (
<>
<div className="bar">
<input
type="text"
aria-label="Search by term"
placeholder="Search"
onChange={({ target: { value } }) => handleTermChange(value)}
/>
</div>
<ul>{posts?.map(post => (<li>{post.title}</li>))}</ul>
</>
);
};
ReactDOM.render(
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>,
document.querySelector('[data-root]')
);
}());
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment