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
getProps only receives params. For request-specific data like searchParams or cookies, fetch data directly inside your components using Suspense with Server Functions to avoid blocking the initial HTML render.
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>
);
}