admin管理员组文章数量:1125034
Prerequisites
- NextJS 14+
- Using server action
- Using app router
- React Query 5+
- Zustand+
Question
I wanted to come up with a design that takes advantage of the best of all the tech above.
Imagine we have a todos app with /todos
page.
What I wanted to happen is during the first page load (request from the client)
The /todos
page is server side rendered. Meaning the todos list on that page is rendered on the server side before being sent to the client.
When the client receives the page, I wanted the react query and zustand to take over. So example, say we have a refresh button on the said page, if we click that button, we fetch the latest todos data via server action using react query so the response is cached, then after getting the data, set it on zustand store.
Then moving forward, we will use data from the zustand store to populate the todos data on the todos table.
Been researching for a while now but I couldn't think of anything else other than passing the todos data from the server side page to the client todos component as a property, but this renders the todos data on the client side and not server side so, I am not even sure if my question is possible or is my intention makes any sense.
Any help is appreciated. Thanks in advance.
Prerequisites
- NextJS 14+
- Using server action
- Using app router
- React Query 5+
- Zustand+
Question
I wanted to come up with a design that takes advantage of the best of all the tech above.
Imagine we have a todos app with /todos
page.
What I wanted to happen is during the first page load (request from the client)
The /todos
page is server side rendered. Meaning the todos list on that page is rendered on the server side before being sent to the client.
When the client receives the page, I wanted the react query and zustand to take over. So example, say we have a refresh button on the said page, if we click that button, we fetch the latest todos data via server action using react query so the response is cached, then after getting the data, set it on zustand store.
Then moving forward, we will use data from the zustand store to populate the todos data on the todos table.
Been researching for a while now but I couldn't think of anything else other than passing the todos data from the server side page to the client todos component as a property, but this renders the todos data on the client side and not server side so, I am not even sure if my question is possible or is my intention makes any sense.
Any help is appreciated. Thanks in advance.
Share Improve this question asked 2 days ago Jplus2Jplus2 2,5134 gold badges35 silver badges58 bronze badges 02 Answers
Reset to default 0we fetch the latest todos data via server action using react query so the response is cached, then after getting the data, set it on zustand store.
I don't understand why you're piping data from RQ to Zustand here. Just use the RQ data directly.
You need to create a RQ client on the server side, populate it with prefetched data, dehydrate and provide it. This way you can access to those data on both server & client side codes by RQ hooks and APIs.
e.g:
const USERS_LIST_RQ_KEY = ['users-list']
const UsersPage = async () => {
const [queryClient] = useState(() => new QueryClient());
const users = await apiClient.users.getList();
await queryClient.setQueryData(USERS_LIST_RQ_KEY, users);
return (
<HydrationBoundary state={dehydrate(queryClient)}>
<UsersTable />
</HydrationBoundary>
);
}
const UsersTable = () => {
const { data } = useQuery({
queryKey: USERS_LIST_RQ_KEY,
queryFn: apiClient.users.getList
});
return (...)
}
Here you will have a server side rendered page, for further user list requests like for pagination and filtration, just do it on the client side. This way, you can handle the loading state better and avoid using server resources, since only the initial page load needs SSR, right?
Read more here: https://tanstack.com/query/latest/docs/framework/react/guides/ssr
And If you want to manage the data with Zustand instead of RQ, there are good examples in the docs on how to initialize the store on the server:
https://zustand.docs.pmnd.rs/guides/nextjs
Zustand Store
import { create } from 'zustand';
const useTodosStore = create((set) => ({ todos: [], setTodos: (todos) => set({ todos }), }));
export default useTodosStore;
React Query Setup
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { Hydrate } from '@tanstack/react-query';
const queryClient = new QueryClient();
function MyApp({ Component, pageProps }) { return ( <Component {...pageProps} /> ); }
export default MyApp;
todos Page (Server + Client) Server Action (Server-Side Rendering)
export async function getTodos() { const res = await fetch('https://jsonplaceholder.typicode.com/todos'); if (!res.ok) throw new Error('Failed to fetch todos'); return await res.json(); }
Page Component
import { dehydrate, QueryClient, useQuery } from '@tanstack/react-query';
import useTodosStore from '../stores/todosStore';
import { getTodos } from '../lib/todos'; // Server action
export async function getServerSideProps() {
const queryClient = new QueryClient();
// Prefetch todos on the server
await queryClient.prefetchQuery(['todos'], getTodos);
return {
props: {
dehydratedState: dehydrate(queryClient), // Pass preloaded data to client
},
};
}
export default function Todos() {
const { todos, setTodos } = useTodosStore();
// React Query fetches or uses preloaded data
const { data: fetchedTodos } = useQuery(['todos'], getTodos, {
onSuccess: (data) => {
// Populate Zustand store on success
setTodos(data);
},
});
const refreshTodos = () => {
// Fetch and update Zustand store
getTodos().then((newTodos) => {
setTodos(newTodos);
});
};
const todosList = todos.length ? todos : fetchedTodos;
return (
<div>
<h1>Todos</h1>
<button onClick={refreshTodos}>Refresh</button>
<ul>
{todosList.map((todo) => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
</div>
);
}
Server-Side Rendering:
getServerSideProps uses getTodos() to fetch data server-side. The fetched data is passed to the client using React Query's hydration (dehydratedState). React Query:
useQuery ensures React Query manages the API calls and caches the data. On a successful fetch, the Zustand store (setTodos) is updated. Zustand Store:
The Zustand store holds the current todos state after React Query fetches data. Clicking "Refresh" bypasses React Query's cache (direct server call) and updates Zustand. Initial Data Flow:
On the first load, data comes from SSR via React Query. On subsequent interactions (e.g., refresh), React Query fetches new data and updates Zustand.
本文标签: nextjsNextJSReact QueryZustandStack Overflow
版权声明:本文标题:next.js - NextJS + React Query + Zustand - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736655794a1946249.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论