diff --git a/README.md b/README.md index 1c2f5cc..32d1909 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,19 @@ The main function of the app or just a file is defined by `export default`. The layout of the app is defined in `layout.js`. The content of `layout.js` is shared between all pages. +## Imports +When importing function and components from other files, there can be named & default imports. Default imports are when you import the default function of a file which was defined by `export default function`. + +Default import +```tsx +import LatestInvoices from '../ui/dashboard/latest-invoices'; +``` + +Named import +```tsx +import { fetchRevenue } from '../lib/data'; +``` + ## Styling In `global.css` some global CSS styling rules were defined. Usally this file is imported in the root layout of the app `layout.js`/`layout.jsx`/`layout.tsx`. @@ -316,6 +329,54 @@ export default function NavLinks() { } ``` +## Data rendering behaviors +There are two ways of fetching data in Next.js. +- static rendering +- dynamic rendering + +Static rendering means that data is fetch while building the app or when the data is revalidating. On each access the cached data will be served. This has the advantage, that the server load can be reduced and the app is faster. Also it has advantages in point of SEO, because there has nothing to be loaded from the server except the page itself. + +But this approach isn't useful when personalized data should be shown. There comes dynamic rendering into play. +Dynamic rendering enables to render real time data and personalized content for each user. It's also possible to show infos about the request. + +### Data streaming +Data streaming enables you to transfer data to the client in more smaller chunks instead of one full package. So the users see the content, that is already ready and in the background the rest is loaded. So the app feels faster and the user can begin using it earlier. Also the data can be rendered in parellel, instead of waiting until each request is finished. + +By adding a `loading.tsx`-File with a `Loading()` component to the app, the streaming can be enabled. +```tsx +export default function Loading(){ + return
Dashboard page
; -} \ No newline at end of file diff --git a/dashboard-app-course/app/query/route.ts b/dashboard-app-course/app/query/route.ts index 0701b73..adc27f8 100644 --- a/dashboard-app-course/app/query/route.ts +++ b/dashboard-app-course/app/query/route.ts @@ -1,26 +1,22 @@ -// import postgres from 'postgres'; +import postgres from 'postgres'; -// const sql = postgres(process.env.POSTGRES_URL!, { ssl: 'require' }); +const sql = postgres(process.env.POSTGRES_URL!, { ssl: 'require' }); -// async function listInvoices() { -// const data = await sql` -// SELECT invoices.amount, customers.name -// FROM invoices -// JOIN customers ON invoices.customer_id = customers.id -// WHERE invoices.amount = 666; -// `; +async function listInvoices() { + const data = await sql` + SELECT invoices.amount, customers.name + FROM invoices + JOIN customers ON invoices.customer_id = customers.id + WHERE invoices.amount = 666; + `; -// return data; -// } + return data; +} export async function GET() { - return Response.json({ - message: - 'Uncomment this file and remove this line. You can delete this file when you are finished.', - }); - // try { - // return Response.json(await listInvoices()); - // } catch (error) { - // return Response.json({ error }, { status: 500 }); - // } + try { + return Response.json(await listInvoices()); + } catch (error) { + return Response.json({ error }, { status: 500 }); + } } diff --git a/dashboard-app-course/app/ui/dashboard/cards.tsx b/dashboard-app-course/app/ui/dashboard/cards.tsx index 526e6f9..dfb5aa2 100644 --- a/dashboard-app-course/app/ui/dashboard/cards.tsx +++ b/dashboard-app-course/app/ui/dashboard/cards.tsx @@ -5,6 +5,7 @@ import { InboxIcon, } from '@heroicons/react/24/outline'; import { lusitana } from '@/app/ui/fonts'; +import { fetchCardData } from '@/app/lib/data'; const iconMap = { collected: BanknotesIcon, @@ -14,18 +15,23 @@ const iconMap = { }; export default async function CardWrapper() { + const { + numberOfInvoices, + numberOfCustomers, + totalPaidInvoices, + totalPendingInvoices, + } = await fetchCardData(); + return ( <> - {/* NOTE: Uncomment this code in Chapter 9 */} - - {/*No data available.
; - // } + if (!revenue || revenue.length === 0) { + returnNo data available.
; + } return (