← Torna al blog

Dev Tips

Un trucchetto al giorno leva le complicazioni di torno! Piccole "scorciatoie" che possono facilitare la vita degli sviluppatori e far risparmiare tempo...e righe di codice.

136

Contenuti dinamici sempre visibili

2025-06-18

Contenuti dinamici visibili… anche senza JavaScript? Sì, si può! Attraverso il Server-Side Rendering (SSR) o Static Site Generation (SSG) e l'idratazione (con HydrationBoundary di TanStack Query), inviamo HTML completo con dati al browser. Se JavaScript è disattivato, l'utente (o il crawler) vedono il contenuto statico. Se attivo, TanStack Query "recupera" quei dati senza una nuova richiesta, offrendo un'esperienza dinamica e fluida. Un ottimo approccio per liste di prodotti, articoli, pagine con dati dinamici ma ad alta visibilità.

1//app/reactQueryProvider.tsx
2'use client';
3import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
4import React from 'react';
5
6export default function ReactQueryProvider({ children }: { children: React.ReactNode }) {
7// Istanza client-side di QueryClient (spesso globalizzata per persistenza)
8  const [queryClient] = React.useState(() => new QueryClient())
9
10  return ( 
11    <QueryClientProvider client={queryClient}>
12      {children}
13    </QueryClientProvider>
14  )
15}
16
17// app/layout.tsx (Configurazione del provider principale)
18import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
19import ReactQueryProvider from "./reactQueryProvider";
20
21export default function RootLayout({ children }: { children: React.ReactNode }) {
22  return (
23    <html lang="it">
24      <body>
25        <ReactQueryProvider>
26          {children} {/* HydrationBoundary sarà gestito nel componente pagina o un wrapper */}
27        </ReactQueryProvider>
28      </body>
29    </html>
30  );
31}
32
33// app/page.tsx (Componente Server-Side per Data Fetching e Rendering Iniziale)
34import { QueryClient, dehydrate, HydrationBoundary } from '@tanstack/react-query';
35import { MyClientList } from '../components/MyClientList';
36
37// Dati di esempio pre-caricati e renderizzati staticamente
38const serverFetchedData = [{ id: 1, name: 'Articolo A (Dal Server)' }];
39
40export default async function HomePage() {
41  // Crea una nuova istanza di QueryClient per ogni richiesta sul server
42  const queryClient = new QueryClient(); 
43
44  // Pre-fetch dei dati sul server (popola la cache di questa istanza di QueryClient)
45  await queryClient.prefetchQuery({
46    queryKey: ['articoli'],
47    queryFn: async () => {
48      console.log('SERVER: Prefetching per App Router...');
49      return serverFetchedData;
50    },
51  });
52
53  return (
54    <div>
55      {/* 1. Rendering statico per il fallback senza JS (incluso nell'HTML iniziale) */}
56      <h3>Contenuto Iniziale (HTML Server-Rendered)</h3>
57      <ul>
58        {serverFetchedData.map(item => (
59          <li key={item.id}>{item.name}</li>
60        ))}
61      </ul>
62
63      <hr />
64
65      {/* 2. Hydration Boundary: avvolge il componente client, passandogli lo stato */}
66      {/* `dehydrate(queryClient)` serializza la cache del server per il client */}
67      <HydrationBoundary state={dehydrate(queryClient)}>
68        <MyClientList /> {/* Questo componente userà useQuery, trovando i dati in cache */}
69      </HydrationBoundary>
70    </div>
71  );
72}
73
74// components/MyClientList.tsx (Il tuo Componente Client-Side che usa useQuery)
75'use client';
76import { useQuery } from '@tanstack/react-query';
77
78const fetchClientData = async () => { 
79  console.log('CLIENT: Fetching (se non idratato)...'); 
80  return [{id: 101, name: 'Articolo X (Client)'}]; 
81};
82
83export function MyClientList() {
84  const { data } = useQuery({ queryKey: ['articoli'], queryFn: fetchClientData });
85  return (
86    <>
87      <h3>Contenuto Idratato (Client-Side)</h3>
88      <ul>{data?.map(item => <li key={item.id}>{item.name}</li>)}</ul>
89    </>
90  );
91}
135

The Power of Domain Layer Isolation

2025-03-24

Il segreto di un software scalabile e manutenibile? Separare bene i livelli. Quando la logica di business è mescolata con la UI, il database e altre parti del sistema, tutto diventa confuso: le regole di business sono sparse ovunque, piccole modifiche rischiano di rompere il codice e il progetto diventa difficile da mantenere e scalare. Quando, invece, la logica di business è pulita e isolata, il codice diventa più chiaro e ogni cambiamento meno rischioso. Come questa pratica può salvare il tuo progetto?

1// Infrastructure Layer
2class DatabaseRepository {
3  save(entity: Entity): void { /* Persistence logic */ }
4}
5
6// Domain Layer
7class Order implements Entity {
8  private lineItems: OrderLine[];
9  // Other stuff...
10
11  isEligibleForDiscount(): boolean {
12    // Implementation code
13  }
14
15  applyDiscount(): void {
16    // Implementation code
17  }
18}
19
20// Application Layer
21class OrderService {
22  constructor(private repository: DatabaseRepository) {}
23
24  processOrder(order: Order): void {
25    if (order.isEligibleForDiscount()) {
26      order.applyDiscount();
27    }
28
29    this.repository.save(order);
30  }
31}
134

Knowledge Crunching

2025-02-25

Scrivere codice è facile ma scrivere codice che ha senso è tutta un’altra storia. Creare un buon modello non significa solo scrivere classi e metodi: è un processo di comprensione profonda del dominio che permette di tradurre concetti complessi in codice chiaro e manutenibile. Il Knowledge Crunching è proprio questo: un processo continuo di collaborazione tra sviluppatori ed esperti di dominio, che ci aiuta a perfezionare i modelli del business e a tradurre le complessità del mondo reale in soluzioni software robuste e scalabili. Ecco come dovrebbe essere un blocco di codice con il Knowledge Crunching:

1class Order {
2  private lineItems: OrderLine[] = [];
3  private total: Money;
4  private status = OrderStatus.DRAFT;
5
6  constructor() {
7    this.total = new Money(0, 'EUR');
8  }
9
10  addProduct(product: Product, quantity: Quantity): void {
11    if (this.status === OrderStatus.CONFIRMED) {
12      throw new OrderAlreadyConfirmedError();
13    }
14
15    const lineItem = new OrderLine(product, quantity);
16    this.lineItems = [...this.lineItems, lineItem];
17    this.recalculateTotal();
18  }
19
20  private recalculateTotal(): void {
21    this.total = this.lineItems.reduce(
22      (sum, item) => sum.add(item.calculateSubtotal()),
23      new Money(0, 'EUR')
24    );
25  }
26}
133

Top-level await

2024-10-23

1// users.mjs
2const res = await fetch('https://jsonplaceholder.typicode.com/users');
3const users = res.json();
4export { users };
5
6//module.mjs
7import {users} from './users.mjs';
8
9console.log(users);
132

Using requestIdleCallback for scheduling low-priority background tasks

2024-07-22

1// Using requestIdleCallback for scheduling low-priority background tasks
2const idleCallback = () => {
3  // Perform background tasks
4  console.log('Background task executed');
5};
6
7window.requestIdleCallback(idleCallback);

Contattaci.

Hai in mente un progetto e vorresti realizzarlo?
Sei interessato a migliorare le competenze del tuo team in ambito di programmazione e sviluppo?
Oppure vuoi semplicemente prendere prendere un caffè con noi e vedere la nostra collezione di Action Figure, allora scrivici tramite questo form.

Se, invece, vuoi far parte del team, guarda le nostre offerte di lavoro.

Questo sito è protetto da reCAPTCHA e si applicano le Norme sulla privacy e i Termini di servizio di Google.