Data Fetching
Dinou offers two main strategies for data fetching: traditional with Server Components and advanced with Suspense combined with Server Functions for reactive experiences.
Without Suspense (Traditional Strategy)
Ideal for static pages or data that doesn't change frequently. This strategy blocks rendering until all data is available.
Server Components (Async Data)
Define async functions to fetch data directly in Server Components without sending logic to the client.
// src/blog/page.jsx
import db from "@/lib/db";
export default async function Page() {
const posts = await db.query("SELECT * FROM posts");
return (
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}Fetch data on the server for security and performance. No client-side fetching needed.
Using getProps (Data Injection)
For static pages or route-based data, use getPropsin page_functions.ts to inject data into your pages and layouts.
// src/blog/[slug]/page_functions.ts
export async function getProps(params) {
// 1. Fetch data based on the URL path (e.g., /blog/my-post)
const post = await db.getPost(params.slug);
// 2. Return data.
// 'page' props go to page.jsx
// 'layout' props go to layout.jsx (useful for setting document titles dynamically)
return {
page: { post },
layout: { title: post.title },
};
}Design Note: Parameter vs. Server Context
While getProps only receives the route params as its parameter, you can still read cookies, headers, or query parameters by calling getContext() since the function executes on the server.
Performance Trade-off:
Because getProps blocks the rendering process at request time, the server waits for it to resolve before starting the render. Keep it fast for dynamic routes; pre-rendered static pages (SSG) are unaffected since their data is fetched at server startup. In Incremental Static Generation (ISG), it only blocks the very first request by the first visitor before the page is cached. If you need slow dynamic fetches on dynamic routes, defer them to a Suspense boundary wrapping a Server Function.
With Suspense (react-enhanced-suspense) & Server Functions (Reactive Strategy)
For fluid user experiences with progressive loading and automatic updates when dependencies change. This strategy combines Suspense with Server Functions for optimal performance.
Client Components with Server Functions (Reactive Updates)
In Client Components, use react-enhanced-suspense to automatically re-fetch Server Functions when dependencies change via the resourceId prop.
// src/[id]/page.jsx
"use client";
import { getPost } from "@/server-functions/get-post";
import Suspense from "react-enhanced-suspense";
export default function Page({ params: { id } }) {
return (
<Suspense fallback="Loading post..." resourceId={`get-post-${id}`}>
{() => getPost(id)}
</Suspense>
);
}react-enhanced-suspense Behavior
Standard Mode: With only children (React Nodes) and fallback, behaves like React's native Suspense.
Enhanced Mode: With resourceId and children as a function, automatically re-evaluates when resourceId changes. No useEffect needed!
The resourceId acts as a cache key. Change it to trigger fresh data fetching without manual cleanup or effect dependencies.
Server Components with Server Functions (Streaming)
In Server Components, wrap Server Function calls to stream results to the client as they become available. Server Functions execute on the server, and Suspense streams the results.
// src/[id]/page.jsx
import { getPost } from "@/server-functions/get-post";
import Suspense from "react-enhanced-suspense";
export default async function Page({ params: { id } }) {
return (
<div>
<Suspense fallback="Loading post...">
{getPost(id)}
</Suspense>
</div>
);
}resourceId key and passing children as a function (e.g. {() => getPost(id)}) to trigger client-side reactive re-fetches when dependencies change.resourceId, and wraps the direct Promise invocation as a child (e.g. {getPost(id)}) to perform server-side HTML streaming.Performance Tip: Static Shell + Dynamic Fetching
Suspense. The browser downloads the static page shell instantly, and the Server Function fetches the dynamic parts on-demand.