I have a CSS grid that loads a server preloaded first page and also uses usePaginatedQuery. I want to make a loading state, but only when the results of usePaginatedQuery are displayed. If the preloaded results are displayed, there should be no loading state. Also I want the transition of the properties updating on the grid to be clean. Currently the properties just vanish and it's not ideal. This grid is displayed properties (buildings) in Virginia.
#CSS grid loading state
5 messages · Page 1 of 1 (latest)
Hi @late flame. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:
To achieve a smooth loading state for your CSS grid that only appears when usePaginatedQuery is fetching data (and not when displaying server-preloaded results), you need to carefully manage when you show the loading indicator and how you transition between states.
Key Points from Convex Documentation
- usePaginatedQuery returns an object with
results,isLoading, andstatus. TheisLoadingflag istruewhen the hook is loading results, andfalseotherwise. Theresultsarray contains the currently loaded items, which will be empty until the first page is loaded unless you hydrate it with preloaded data yourself [Paginating within React Components]. - If you want to avoid a flash or abrupt disappearance of grid items when loading new data, you can use a "stable" query pattern. This involves keeping the previous results visible until the new data is ready, as shown in the
useStablePaginatedQueryexample [What about pagination, is that a complication?].
Implementation Strategy
- Hydrate the grid with preloaded data: Render your preloaded properties as the initial state of the grid.
- Use usePaginatedQuery for subsequent data: When the hook loads, only show the loading state if the grid is displaying data from usePaginatedQuery and not from the preloaded data.
- Keep previous results during loading: Use a stable paginated query pattern to avoid abrupt transitions or empty states while new data is loading.
- CSS Transitions: Use CSS transitions or animations to smoothly update the grid when new properties are loaded.
Example Approach
import { useRef } from "react";
import { usePaginatedQuery } from "convex/react";
import { api } from "../convex/_generated/api";
// Custom hook to keep previous results during loading
function useStablePaginatedQuery(query, args, options, preloadedResults) {
const result = usePaginatedQuery(query, args, options);
const stored = useRef({ ...result, results: preloadedResults });
// Only update stored results when not loading more
if (result.status !== "LoadingMore" && result.status !== "LoadingFirstPage") {
stored.current = result;
}
return stored.current;
}
export function PropertiesGrid({ preloadedProperties }) {
const { results, status, isLoading, loadMore } = useStablePaginatedQuery(
api.properties.listInVirginia,
{},
{ initialNumItems: 20 },
preloadedProperties
);
// Show loading indicator only if not showing preloaded data
const showLoading = isLoading && results !== preloadedProperties;
return (
<div className={`grid properties-grid ${showLoading ? "loading" : ""}`}>
{results.map((property) => (
<PropertyCard key={property._id} {...property} />
))}
{showLoading && <div className="loading-indicator">Loading...</div>}
{status === "CanLoadMore" && (
<button onClick={() => loadMore(20)}>Load More</button>
)}
</div>
);
}
CSS Example for Smooth Transitions
.properties-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 1rem;
transition: opacity 0.3s;
}
.properties-grid.loading {
opacity: 0.5;
}
.loading-indicator {
grid-column: 1 / -1;
text-align: center;
animation: fadeIn 0.3s;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
Summary
- Hydrate your grid with preloaded data.
- Use a stable paginated query pattern to avoid flashes or abrupt transitions.
- Only show the loading state when usePaginatedQuery is fetching and not when preloaded data is displayed.
- Use CSS transitions for a smooth UI update.