Heim > Web-Frontend > js-Tutorial > Von Next.js zu React Edge mit Cloudflare Workers: Eine Befreiungsgeschichte

Von Next.js zu React Edge mit Cloudflare Workers: Eine Befreiungsgeschichte

DDD
Freigeben: 2024-11-20 13:58:12
Original
923 Leute haben es durchsucht
  • Der letzte Strohhalm
  • Die Alternative mit Cloudflare?
  • React Edge: Das React Framework, das aus allen (oder fast) den Aufgaben eines Entwicklers entstanden ist
    • Die Magie des typisierten RPC
    • Die Kraft von useFetch: Where the Magic Happens
  • UnbrauchbarFetch: Das komplette Arsenal
    • RPC: Die Kunst der Client-Server-Kommunikation
    • Ein i18n-System, das Sinn macht
    • JWT-Authentifizierung, die „einfach funktioniert“
    • Der Shared Store
    • Elegantes Routing
    • Verteilter Cache mit Edge-Cache
  • Link: Die vorausschauende Komponente
  • app.useContext: Das Gateway zu Edge
  • app.useUrlState: Status mit URL synchronisiert
  • app.useStorageState: Persistenter Zustand
  • app.useDebounce: Frequenzsteuerung
  • app.useDistinct: Status ohne Duplikate
  • Die React Edge CLI: Leistung immer zur Hand
  • Fazit

Der letzte Tropfen

Alles begann mit einer Rechnung von Vercel. Nein, eigentlich fing es viel früher an – mit kleinen Frustrationen, die sich anhäuften. Die Notwendigkeit, für grundlegende Funktionen wie DDoS-Schutz, detailliertere Protokolle oder sogar eine anständige Firewall, Build-Warteschlangen usw. zu bezahlen. Das Gefühl, in einer immer teurer werdenden Lieferantenbindung gefangen zu sein.

„Und das Schlimmste: Unsere wertvollen SEO-Header wurden einfach nicht mehr auf dem Server in einer Anwendung gerendert, die den Seitenrouter verwendet. Ein echtes Problem für jeden Entwickler!?“

Aber was mich wirklich zum Umdenken brachte, war die Richtung, in die Next.js ging. Die Einführung von Usage-Client- und Usage-Server-Anweisungen, die theoretisch die Entwicklung vereinfachen sollten, in der Praxis jedoch eine weitere Ebene der Komplexität bei der Verwaltung hinzufügten. Es war, als würden wir in die Zeit von PHP zurückkehren und Dateien mit Anweisungen markieren, um ihnen mitzuteilen, wo sie ausgeführt werden sollen.

Und dabei hört es noch nicht auf. Der App Router, eine interessante Idee, aber so umgesetzt, dass ein praktisch neues Framework innerhalb von Next.js entstand. Plötzlich hatten wir zwei völlig unterschiedliche Möglichkeiten, dasselbe zu tun. Das „Alte“ und das „Neue“ – mit subtil unterschiedlichen Verhaltensweisen und versteckten Fallen.

Die Alternative mit Cloudflare?

Da wurde mir klar: Warum nicht die unglaubliche Infrastruktur von Cloudflare nutzen, mit Workern, die am Edge laufen, R2 für die Speicherung, KV für verteilte Daten ... Und natürlich den unglaublichen DDoS-Schutz, das globale CDN, die Firewall und die Regeln für Seiten und Routen und alles andere, was Cloudflare bietet.

Und das Beste: ein faires Preismodell, bei dem Sie für das bezahlen, was Sie nutzen, ohne Überraschungen.

So wurde React Edge geboren. Ein Framework, das nicht versucht, das Rad neu zu erfinden, sondern vielmehr ein wirklich einfaches und modernes Entwicklungserlebnis bietet.

React Edge: Das React Framework, das aus allen (oder fast) den Aufgaben eines Entwicklers entstanden ist

Als ich mit der Entwicklung von React Edge begann, hatte ich ein klares Ziel: ein Framework zu schaffen, das Sinn macht. Sie müssen sich nicht mehr mit verwirrenden Anweisungen abmühen, müssen kein Vermögen mehr für Grundfunktionen ausgeben und, was am wichtigsten ist, Sie müssen sich nicht mehr mit der künstlichen Komplexität herumschlagen, die durch die Trennung von Client und Server entsteht. Ich wollte Geschwindigkeit, etwas, das Leistung liefert, ohne auf Einfachheit zu verzichten. Dank meiner Kenntnisse der React-API und meiner jahrelangen Erfahrung als Javascript- und Golang-Entwickler wusste ich genau, wie man mit Streams und Multiplexing umgeht, um das Rendering und die Datenverwaltung zu optimieren.

Cloudflare Workers bot mir mit seiner leistungsstarken Infrastruktur und globalen Präsenz die perfekte Umgebung, um diese Möglichkeiten zu erkunden. Ich wollte etwas, das wirklich hybrid ist, und diese Kombination aus Tools und Erfahrung hat React Edge zum Leben erweckt: ein Framework, das echte Probleme mit modernen und effizienten Lösungen löst.

React Edge bietet einen revolutionären Ansatz für die React-Entwicklung. Stellen Sie sich vor, Sie könnten eine Klasse auf dem Server schreiben und sie direkt vom Client aufrufen, mit vollständiger Typisierung und ohne Konfiguration. Stellen Sie sich ein verteiltes Caching-System vor, das „einfach funktioniert“ und die Ungültigmachung durch Tags oder Präfixe ermöglicht. Stellen Sie sich vor, Sie könnten den Status zwischen Server und Client auf transparente und sichere Weise teilen. Neben der Vereinfachung der Authentifizierung und der Bereitstellung eines effizienten Internationalisierungsansatzes, CLI und vielem mehr.

Ihre RPC-Kommunikation ist so natürlich, dass sie wie Magie wirkt – Sie schreiben Methoden in einer Klasse und rufen sie vom Client aus auf, als wären sie lokal. Das intelligente Multiplexing-System stellt sicher, dass auch bei gleichzeitigem Aufruf mehrerer Komponenten nur eine Anfrage an den Server gestellt wird. Der ephemere Cache vermeidet unnötige wiederholte Anfragen und das alles funktioniert sowohl auf dem Server als auch auf dem Client.

Einer der mächtigsten Punkte ist der app.useFetch-Hook, der das Datenabruferlebnis vereinheitlicht. Auf dem Server werden während der SSR Daten vorab geladen. Auf dem Client versorgt es sich automatisch mit diesen Daten und ermöglicht Aktualisierungen bei Bedarf. Und mit der Unterstützung für automatische Abfragen und abhängigkeitsbasierte Reaktivität war die Erstellung dynamischer Schnittstellen noch nie so einfach.

Aber das ist noch nicht alles. Das Framework bietet ein leistungsstarkes Routing-System (inspiriert vom fantastischen Hono), eine in Cloudflare R2 integrierte Asset-Verwaltung und eine elegante Möglichkeit zur Fehlerbehandlung über die HttpError-Klasse. Middleware kann Daten problemlos über einen gemeinsamen Speicher an den Client senden, und alles wird aus Sicherheitsgründen automatisch verschleiert.

Das Beeindruckendste? Fast der gesamte Code des Frameworks ist hybrid. Es gibt keine „Client“- und keine „Server“-Version – derselbe Code funktioniert in beiden Umgebungen und passt sich automatisch an den Kontext an. Der Kunde erhält nur das, was er benötigt, wodurch das endgültige Paket äußerst optimiert wird.

Und das Tüpfelchen auf dem i: All dies läuft auf der Edge-Infrastruktur von Cloudflare Workers und bietet außergewöhnliche Leistung zu fairen Kosten. Keine Überraschungen auf der Rechnung, keine grundlegenden Funktionen, die hinter erzwungenen Unternehmensplänen verborgen sind, sondern nur ein solides Framework, das es Ihnen ermöglicht, sich auf das Wesentliche zu konzentrieren: die Erstellung unglaublicher Anwendungen. Darüber hinaus nutzt React Edge das gesamte Cloudflare-Ökosystem, einschließlich Warteschlangen, langlebige Objekte, KV-Speicher und mehr, um eine robuste, skalierbare Grundlage für Ihre Anwendungen bereitzustellen.

Vite wurde als Basis verwendet, sowohl für die Entwicklungsumgebung als auch zum Testen und Erstellen. Vite ermöglicht mit seiner beeindruckenden Geschwindigkeit und modernen Architektur einen agilen und effizienten Workflow. Es beschleunigt nicht nur die Entwicklung, sondern optimiert auch den Build-Prozess und stellt sicher, dass der Code schnell und genau kompiliert wird. Ohne Zweifel war Vite die perfekte Wahl für React Edge.

React-Entwicklung für das Edge-Computing-Zeitalter neu denken

Haben Sie sich jemals gefragt, wie es wäre, React-Anwendungen zu entwickeln, ohne sich um die Client/Server-Barriere kümmern zu müssen? Ohne sich Dutzende von Anweisungen wie „Use Client“ oder „Use Server“ merken zu müssen? Und noch besser: Was wäre, wenn Sie Serverfunktionen so aufrufen könnten, als wären sie lokal, mit vollständiger Eingabe und ohne Konfiguration?

Mit React Edge müssen Sie nicht:

  • Erstellen Sie separate API-Routen
  • Lade-/Fehlerstatus manuell verwalten
  • Entprellung manuell durchführen
  • Sorgen wegen Serialisierung/Deserialisierung
  • Cors handhaben
  • Verwalten Sie die Eingabe zwischen Client/Server
  • Authentifizierungsregeln manuell verwalten
  • Verwalten Sie, wie die Internationalisierung durchgeführt wird

Und das Beste daran: Das alles funktioniert sowohl auf dem Server als auch auf dem Client, ohne dass irgendetwas mit „Use Client“ oder „Use Server“ markiert werden muss. Das Framework weiß je nach Kontext, was zu tun ist. Sollen wir gehen?

Die Magie des typisierten RPC

Stellen Sie sich vor, Sie könnten Folgendes tun:

// No servidor
class UserAPI extends Rpc {
  async searchUsers(query: string, filters: UserFilters) {
    // Validação com Zod
    const validated = searchSchema.parse({ query, filters });
    return this.db.users.search(validated);
  }
}

// No cliente
const UserSearch = () => {
  const { rpc } = app.useContext<App.Context>();

  // TypeScript sabe exatamente o que searchUsers aceita e retorna!
  const { data, loading, error, fetch: retry } = app.useFetch(
    async (ctx) => ctx.rpc.searchUsers('John', { age: '>18' })
  );
};
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Vergleichen Sie dies mit Next.js/Vercel:

// pages/api/search.ts
export default async handler = (req, res) => {
  // Configurar CORS
  // Validar request
  // Tratar erros
  // Serializar resposta
  // ...100 linhas depois...
}

// app/search/page.tsx
'use client';
import { useEffect, useState } from 'react';

export default const SearchPage = () => {
  const [search, setSearch] = useState('');
  const [filters, setFilters] = useState({});
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    let timeout;
    const doSearch = async () => {
      setLoading(true);
      try {
        const res = await fetch('/api/search?' + new URLSearchParams({
          q: search,
          ...filters
        }));
        if (!res.ok) throw new Error('Search failed');
        setData(await res.json());
      } catch (err) {
        console.error(err);
      } finally {
        setLoading(false);
      }
    };

    timeout = setTimeout(doSearch, 300);
    return () => clearTimeout(timeout);
  }, [search, filters]);

  // ... resto do componente
}
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Die Kraft von useFetch: Wo die Magie passiert

Datenabruf neu gedacht

Vergessen Sie alles, was Sie über das Abrufen von Daten in React wissen. app.useFetch von React Edge bringt einen völlig neuen und leistungsstarken Ansatz. Stellen Sie sich einen Haken vor, der:

  • Daten während der SSR vorab auf den Server laden
  • Spendet dem Kunden automatisch Feuchtigkeit, ohne zu flackern
  • Behält die vollständige Eingabe zwischen Client und Server bei
  • Unterstützt Reaktivität mit Smart Debounce
  • Automatisch multiplexiert identische Anrufe
  • Ermöglicht programmatische Aktualisierungen und Abfragen

Sehen wir uns das in Aktion an:

// No servidor
class UserAPI extends Rpc {
  async searchUsers(query: string, filters: UserFilters) {
    // Validação com Zod
    const validated = searchSchema.parse({ query, filters });
    return this.db.users.search(validated);
  }
}

// No cliente
const UserSearch = () => {
  const { rpc } = app.useContext<App.Context>();

  // TypeScript sabe exatamente o que searchUsers aceita e retorna!
  const { data, loading, error, fetch: retry } = app.useFetch(
    async (ctx) => ctx.rpc.searchUsers('John', { age: '>18' })
  );
};
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Die Magie des Multiplexings

Das obige Beispiel verbirgt eine leistungsstarke Funktion: intelligentes Multiplexing. Wenn Sie ctx.rpc.batch verwenden, führt React Edge die Aufrufe nicht nur stapelweise durch, sondern dedupliziert automatisch identische Aufrufe:

// pages/api/search.ts
export default async handler = (req, res) => {
  // Configurar CORS
  // Validar request
  // Tratar erros
  // Serializar resposta
  // ...100 linhas depois...
}

// app/search/page.tsx
'use client';
import { useEffect, useState } from 'react';

export default const SearchPage = () => {
  const [search, setSearch] = useState('');
  const [filters, setFilters] = useState({});
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    let timeout;
    const doSearch = async () => {
      setLoading(true);
      try {
        const res = await fetch('/api/search?' + new URLSearchParams({
          q: search,
          ...filters
        }));
        if (!res.ok) throw new Error('Search failed');
        setData(await res.json());
      } catch (err) {
        console.error(err);
      } finally {
        setLoading(false);
      }
    };

    timeout = setTimeout(doSearch, 300);
    return () => clearTimeout(timeout);
  }, [search, filters]);

  // ... resto do componente
}
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

SSR Perfekte Flüssigkeitszufuhr

Einer der beeindruckendsten Teile ist, wie useFetch mit SSR umgeht:

// Primeiro, definimos nossa API no servidor
class PropertiesAPI extends Rpc {
 async searchProperties(filters: PropertyFilters) {
   const results = await this.db.properties.search(filters);
   // Cache automático por 5 minutos
   return this.createResponse(results, {
     cache: { ttl: 300, tags: ['properties'] }
   });
 }

 async getPropertyDetails(ids: string[]) {
   return Promise.all(
     ids.map(id => this.db.properties.findById(id))
   );
 }
}

// Agora, no cliente, a mágica acontece
const PropertySearch = () => {
 const [filters, setFilters] = useState<PropertyFilters>({
   price: { min: 100000, max: 500000 },
   bedrooms: 2
 });

 // Busca reativa com debounce inteligente
 const { 
   data: searchResults,
   loading: searchLoading,
   error: searchError
 } = app.useFetch(
   async (ctx) => ctx.rpc.searchProperties(filters),
   {
     // Quando filters muda, refaz a busca
     deps: [filters],
     // Mas espera 300ms de 'silêncio' antes de buscar
     depsDebounce: {
       filters: 300
     }
   }
 );

 // Agora, vamos buscar os detalhes das propriedades encontradas
 const {
   data: propertyDetails,
   loading: detailsLoading,
   fetch: refreshDetails
 } = app.useFetch(
   async (ctx) => {
     if (!searchResults?.length) return null;

     // Isso parece fazer múltiplas chamadas, mas...
     return ctx.rpc.batch([
       // Na verdade, tudo é multiplexado em uma única requisição!
       ...searchResults.map(result => 
         ctx.rpc.getPropertyDetails(result.id)
       )
     ]);
   },
   {
     // Atualiza sempre que searchResults mudar
     deps: [searchResults]
   }
 );

 // Interface bonita e responsiva
 return (
   <div>
     <FiltersPanel 
       value={filters}
       onChange={setFilters}
       disabled={searchLoading}
     />

     {searchError && (
       <Alert status='error'>
         Erro na busca: {searchError.message}
       </Alert>
     )}

     <PropertyGrid
       items={propertyDetails || []}
       loading={detailsLoading}
       onRefresh={() => refreshDetails()}
     />
   </div>
 );
};
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

UnbrauchbarFetch: Das komplette Arsenal

RPC: Die Kunst der Client-Server-Kommunikation

Sicherheit und Kapselung

Das RPC-System von React Edge wurde im Hinblick auf Sicherheit und Kapselung entwickelt. Nicht alles in einer RPC-Klasse wird dem Client automatisch angezeigt:

const PropertyListingPage = () => {
  const { data } = app.useFetch(async (ctx) => {
    // Mesmo que você faça 100 chamadas idênticas...
    return ctx.rpc.batch([
      ctx.rpc.getProperty('123'),
      ctx.rpc.getProperty('123'), // mesma chamada
      ctx.rpc.getProperty('456'),
      ctx.rpc.getProperty('456'), // mesma chamada
    ]);
  });

  // Mas na realidade:
  // 1. O batch agrupa todas as chamadas em UMA única requisição HTTP
  // 2. Chamadas idênticas são deduplicas automaticamente
  // 3. O resultado é distribuído corretamente para cada posição do array
  // 4. A tipagem é mantida para cada resultado individual!


  // Entao..
  // 1. getProperty('123')
  // 2. getProperty('456')
  // E os resultados são distribuídos para todos os chamadores!
};
Nach dem Login kopieren
Nach dem Login kopieren

RPC-API-Hierarchie

Eine der leistungsstärksten Funktionen von RPC ist die Möglichkeit, APIs in Hierarchien zu organisieren:

const ProductPage = ({ productId }: Props) => {
  const { data, loaded, loading, error } = app.useFetch(
    async (ctx) => ctx.rpc.getProduct(productId),
    {
      // Controle fino de quando executar
      shouldFetch: ({ worker, loaded }) => {
        // No worker (SSR): sempre busca
        if (worker) return true;
        // No cliente: só busca se não tiver dados
        return !loaded;
      }
    }
  );

  // No servidor:
  // 1. useFetch faz a chamada RPC
  // 2. Dados são serializados e enviados ao cliente
  // 3. Componente renderiza com os dados

  // No cliente:
  // 1. Componente hidrata com os dados do servidor
  // 2. Não faz nova chamada (shouldFetch retorna false)
  // 3. Se necessário, pode refazer a chamada com data.fetch()

  return (
    <Suspense fallback={<ProductSkeleton />}>
      <ProductView 
        product={data}
        loading={loading}
        error={error}
      />
    </Suspense>
  );
};
Nach dem Login kopieren
Nach dem Login kopieren

Vorteile der Hierarchie

Die Organisation von APIs in Hierarchien bringt mehrere Vorteile mit sich:

  • Logische Organisation: Gruppieren Sie verwandte Funktionen auf intuitive Weise
  • Natürlicher Namespace: Vermeiden Sie Namenskonflikte mit klaren Pfaden (users.preferences.getTheme)
  • Kapselung: Halten Sie Hilfsmethoden auf jeder Ebene privat
  • Wartbarkeit: Jede Unterklasse kann unabhängig gewartet und getestet werden
  • Vollständige Typisierung: TypeScript versteht die gesamte Hierarchie

Das RPC-System von React Edge macht die Client-Server-Kommunikation so natürlich, dass Sie fast vergessen, dass Sie Remote-Anrufe tätigen. Und mit der Möglichkeit, APIs in Hierarchien zu organisieren, können Sie komplexe Strukturen erstellen und gleichzeitig Ihren Code organisiert und sicher halten.

Ein i18n-System, das Sinn macht

React Edge bietet ein elegantes und flexibles Internationalisierungssystem, das variable Interpolation und komplexe Formatierung ohne umfangreiche Bibliotheken unterstützt.

class PaymentsAPI extends Rpc {
 // Propriedades nunca são expostas
 private stripe = new Stripe(process.env.STRIPE_KEY);

 // Métodos começando com $ são privados
 private async $validateCard(card: CardInfo) {
   return await this.stripe.cards.validate(card);
 }

 // Métodos começando com _ também são privados
 private async _processPayment(amount: number) {
   return await this.stripe.charges.create({ amount });
 }

 // Este método é público e acessível via RPC
 async createPayment(orderData: OrderData) {
   // Validação interna usando método privado
   const validCard = await this.$validateCard(orderData.card);
   if (!validCard) {
     throw new HttpError(400, 'Invalid card');
   }

   // Processamento usando outro método privado
   const payment = await this._processPayment(orderData.amount);
   return payment;
 }
}

// No cliente:
const PaymentForm = () => {
 const { rpc } = app.useContext<App.Context>();

 // ✅ Isso funciona
 const handleSubmit = () => rpc.createPayment(data);

 // ❌ Isso não é possível - métodos privados não são expostos
 const invalid1 = () => rpc.$validateCard(data);
 const invalid2 = () => rpc._processPayment(100);

 // ❌ Isso também não funciona - propriedades não são expostas
 const invalid3 = () => rpc.stripe;
};
Nach dem Login kopieren

Verwendung im Code:

// APIs aninhadas para melhor organização
class UsersAPI extends Rpc {
  // Subclasse para gerenciar preferences
  preferences = new UserPreferencesAPI();
  // Subclasse para gerenciar notificações
  notifications = new UserNotificationsAPI();

  async getProfile(id: string) {
    return this.db.users.findById(id);
  }
}

class UserPreferencesAPI extends Rpc {
  async getTheme(userId: string) {
    return this.db.preferences.getTheme(userId);
  }

  async setTheme(userId: string, theme: Theme) {
    return this.db.preferences.setTheme(userId, theme);
  }
}

class UserNotificationsAPI extends Rpc {
  // Métodos privados continuam privados
  private async $sendPush(userId: string, message: string) {
    await this.pushService.send(userId, message);
  }

  async getSettings(userId: string) {
    return this.db.notifications.getSettings(userId);
  }

  async notify(userId: string, notification: Notification) {
    const settings = await this.getSettings(userId);
    if (settings.pushEnabled) {
      await this.$sendPush(userId, notification.message);
    }
  }
}

// No cliente:
const UserProfile = () => {
  const { rpc } = app.useContext<App.Context>();

  const { data: profile } = app.useFetch(
    async (ctx) => {
      // Chamadas aninhadas são totalmente tipadas
      const [user, theme, notificationSettings] = await ctx.rpc.batch([
        // Método da classe principal
        ctx.rpc.getProfile('123'),
        // Método da subclasse de preferências
        ctx.rpc.preferences.getTheme('123'),
        // Método da subclasse de notificações
        ctx.rpc.notifications.getSettings('123')
      ]);

      return { user, theme, notificationSettings };
    }
  );

  // ❌ Métodos privados continuam inacessíveis
  const invalid = () => rpc.notifications.$sendPush('123', 'hello');
};
Nach dem Login kopieren

Nullkonfiguration

React Edge erkennt und lädt Ihre Übersetzungen automatisch und kann Benutzereinstellungen problemlos in Cookies speichern. Aber damit haben Sie schon gerechnet, oder?

// No servidor
class UserAPI extends Rpc {
  async searchUsers(query: string, filters: UserFilters) {
    // Validação com Zod
    const validated = searchSchema.parse({ query, filters });
    return this.db.users.search(validated);
  }
}

// No cliente
const UserSearch = () => {
  const { rpc } = app.useContext<App.Context>();

  // TypeScript sabe exatamente o que searchUsers aceita e retorna!
  const { data, loading, error, fetch: retry } = app.useFetch(
    async (ctx) => ctx.rpc.searchUsers('John', { age: '>18' })
  );
};
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

JWT-Authentifizierung, die „einfach funktioniert“

Authentifizierung war schon immer ein Problem bei Webanwendungen. Verwaltung von JWT-Tokens, sichere Cookies, erneute Validierung – all dies erfordert normalerweise eine Menge Boilerplate-Code. React Edge ändert dies komplett.

Sehen Sie, wie einfach es ist, ein vollständiges Authentifizierungssystem zu implementieren:

// pages/api/search.ts
export default async handler = (req, res) => {
  // Configurar CORS
  // Validar request
  // Tratar erros
  // Serializar resposta
  // ...100 linhas depois...
}

// app/search/page.tsx
'use client';
import { useEffect, useState } from 'react';

export default const SearchPage = () => {
  const [search, setSearch] = useState('');
  const [filters, setFilters] = useState({});
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    let timeout;
    const doSearch = async () => {
      setLoading(true);
      try {
        const res = await fetch('/api/search?' + new URLSearchParams({
          q: search,
          ...filters
        }));
        if (!res.ok) throw new Error('Search failed');
        setData(await res.json());
      } catch (err) {
        console.error(err);
      } finally {
        setLoading(false);
      }
    };

    timeout = setTimeout(doSearch, 300);
    return () => clearTimeout(timeout);
  }, [search, filters]);

  // ... resto do componente
}
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Client-Nutzung: Keine Konfiguration

// Primeiro, definimos nossa API no servidor
class PropertiesAPI extends Rpc {
 async searchProperties(filters: PropertyFilters) {
   const results = await this.db.properties.search(filters);
   // Cache automático por 5 minutos
   return this.createResponse(results, {
     cache: { ttl: 300, tags: ['properties'] }
   });
 }

 async getPropertyDetails(ids: string[]) {
   return Promise.all(
     ids.map(id => this.db.properties.findById(id))
   );
 }
}

// Agora, no cliente, a mágica acontece
const PropertySearch = () => {
 const [filters, setFilters] = useState<PropertyFilters>({
   price: { min: 100000, max: 500000 },
   bedrooms: 2
 });

 // Busca reativa com debounce inteligente
 const { 
   data: searchResults,
   loading: searchLoading,
   error: searchError
 } = app.useFetch(
   async (ctx) => ctx.rpc.searchProperties(filters),
   {
     // Quando filters muda, refaz a busca
     deps: [filters],
     // Mas espera 300ms de 'silêncio' antes de buscar
     depsDebounce: {
       filters: 300
     }
   }
 );

 // Agora, vamos buscar os detalhes das propriedades encontradas
 const {
   data: propertyDetails,
   loading: detailsLoading,
   fetch: refreshDetails
 } = app.useFetch(
   async (ctx) => {
     if (!searchResults?.length) return null;

     // Isso parece fazer múltiplas chamadas, mas...
     return ctx.rpc.batch([
       // Na verdade, tudo é multiplexado em uma única requisição!
       ...searchResults.map(result => 
         ctx.rpc.getPropertyDetails(result.id)
       )
     ]);
   },
   {
     // Atualiza sempre que searchResults mudar
     deps: [searchResults]
   }
 );

 // Interface bonita e responsiva
 return (
   <div>
     <FiltersPanel 
       value={filters}
       onChange={setFilters}
       disabled={searchLoading}
     />

     {searchError && (
       <Alert status='error'>
         Erro na busca: {searchError.message}
       </Alert>
     )}

     <PropertyGrid
       items={propertyDetails || []}
       loading={detailsLoading}
       onRefresh={() => refreshDetails()}
     />
   </div>
 );
};
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Warum ist das revolutionär?

  1. Null-Boilerplate

    • Keine manuelle Cookie-Verwaltung
    • Keine Abfangjäger erforderlich
    • Kein Upgrade-Token-Handbuch
  2. Standardmäßige Sicherheit

    • Tokens werden automatisch verschlüsselt
    • Cookies sind sicher und nur http
    • Automatische Revalidierung
  3. Schließen Sie die Eingabe ab

    • JWT-Nutzlast wird eingegeben
    • Validierung mit integriertem Zod
    • Eingegebene Authentifizierungsfehler
  4. Nahtlose Integration

const PropertyListingPage = () => {
  const { data } = app.useFetch(async (ctx) => {
    // Mesmo que você faça 100 chamadas idênticas...
    return ctx.rpc.batch([
      ctx.rpc.getProperty('123'),
      ctx.rpc.getProperty('123'), // mesma chamada
      ctx.rpc.getProperty('456'),
      ctx.rpc.getProperty('456'), // mesma chamada
    ]);
  });

  // Mas na realidade:
  // 1. O batch agrupa todas as chamadas em UMA única requisição HTTP
  // 2. Chamadas idênticas são deduplicas automaticamente
  // 3. O resultado é distribuído corretamente para cada posição do array
  // 4. A tipagem é mantida para cada resultado individual!


  // Entao..
  // 1. getProperty('123')
  // 2. getProperty('456')
  // E os resultados são distribuídos para todos os chamadores!
};
Nach dem Login kopieren
Nach dem Login kopieren

Der Shared Store

Eine der leistungsstärksten Funktionen von React Edge ist die Fähigkeit, den Status sicher zwischen Arbeiter und Client zu teilen. Mal sehen, wie das funktioniert:

const ProductPage = ({ productId }: Props) => {
  const { data, loaded, loading, error } = app.useFetch(
    async (ctx) => ctx.rpc.getProduct(productId),
    {
      // Controle fino de quando executar
      shouldFetch: ({ worker, loaded }) => {
        // No worker (SSR): sempre busca
        if (worker) return true;
        // No cliente: só busca se não tiver dados
        return !loaded;
      }
    }
  );

  // No servidor:
  // 1. useFetch faz a chamada RPC
  // 2. Dados são serializados e enviados ao cliente
  // 3. Componente renderiza com os dados

  // No cliente:
  // 1. Componente hidrata com os dados do servidor
  // 2. Não faz nova chamada (shouldFetch retorna false)
  // 3. Se necessário, pode refazer a chamada com data.fetch()

  return (
    <Suspense fallback={<ProductSkeleton />}>
      <ProductView 
        product={data}
        loading={loading}
        error={error}
      />
    </Suspense>
  );
};
Nach dem Login kopieren
Nach dem Login kopieren

Wie es funktioniert

  • Öffentliche Daten: Als öffentlich gekennzeichnete Daten werden sicher mit dem Client geteilt, sodass sie für Komponenten leicht zugänglich sind.
  • Private Daten: Sensible Daten verbleiben in der Arbeitsumgebung und werden niemals dem Kunden zugänglich gemacht.
  • Middleware-Integration: Middleware kann den Speicher mit öffentlichen und privaten Daten füllen und so einen kontinuierlichen Informationsfluss zwischen Serverlogik und clientseitigem Rendering gewährleisten.

Vorteile

  1. Sicherheit: Durch die Trennung von öffentlichen und privaten Datenbereichen wird sichergestellt, dass vertrauliche Informationen geschützt bleiben.
  2. Bequemlichkeit: Der transparente Zugriff auf Speicherdaten vereinfacht die Statusverwaltung zwischen Mitarbeiter und Kunde.
  3. Flexibilität: Der Shop lässt sich problemlos in Middleware integrieren und ermöglicht dynamische Statusaktualisierungen basierend auf der Anfragebearbeitung.

Elegantes Routing

Das Routing-System von React Edge ist von Hono inspiriert, verfügt aber über Superkräfte für SSR:

// No servidor
class UserAPI extends Rpc {
  async searchUsers(query: string, filters: UserFilters) {
    // Validação com Zod
    const validated = searchSchema.parse({ query, filters });
    return this.db.users.search(validated);
  }
}

// No cliente
const UserSearch = () => {
  const { rpc } = app.useContext<App.Context>();

  // TypeScript sabe exatamente o que searchUsers aceita e retorna!
  const { data, loading, error, fetch: retry } = app.useFetch(
    async (ctx) => ctx.rpc.searchUsers('John', { age: '>18' })
  );
};
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Hauptmerkmale

  • Gruppierte Routen: Logische Gruppierung verwandter Routen unter einem gemeinsamen Pfad und einer gemeinsamen Middleware. Flexible Handler: Definieren Sie Handler, die Seiten oder direkte API-Antworten zurückgeben.
  • Pro-Route-Header: Passen Sie HTTP-Header für einzelne Routen an.
  • Integrierter Cache: Vereinfachen Sie Caching-Strategien mit TTL und Tags.

Vorteile

  1. Konsistenz: Durch die Gruppierung verwandter Routen stellen Sie eine konsistente Middleware-Anwendung und Code-Organisation sicher.
  2. Skalierbarkeit: Das System unterstützt verschachteltes und modulares Routing für große Anwendungen.
  3. Leistung: Native Cache-Unterstützung sorgt für optimale Reaktionszeiten ohne manuelle Konfigurationen.

Verteilter Cache mit Edge-Cache

React Edge verfügt über ein leistungsstarkes Caching-System, das sowohl für JSON-Daten als auch für ganze Seiten funktioniert:

// pages/api/search.ts
export default async handler = (req, res) => {
  // Configurar CORS
  // Validar request
  // Tratar erros
  // Serializar resposta
  // ...100 linhas depois...
}

// app/search/page.tsx
'use client';
import { useEffect, useState } from 'react';

export default const SearchPage = () => {
  const [search, setSearch] = useState('');
  const [filters, setFilters] = useState({});
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    let timeout;
    const doSearch = async () => {
      setLoading(true);
      try {
        const res = await fetch('/api/search?' + new URLSearchParams({
          q: search,
          ...filters
        }));
        if (!res.ok) throw new Error('Search failed');
        setData(await res.json());
      } catch (err) {
        console.error(err);
      } finally {
        setLoading(false);
      }
    };

    timeout = setTimeout(doSearch, 300);
    return () => clearTimeout(timeout);
  }, [search, filters]);

  // ... resto do componente
}
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Hauptmerkmale

  • Tag-basierte Ungültigmachung: Cache-Einträge können mithilfe von Tags gruppiert werden, was eine einfache und selektive Ungültigmachung bei Datenänderungen ermöglicht.
  • Präfixübereinstimmung: Machen Sie mehrere Cache-Einträge mithilfe eines gemeinsamen Präfixes ungültig, ideal für Szenarien wie Suchanfragen oder hierarchische Daten.
  • Time to Live (TTL): Legen Sie Ablaufzeiten für Cache-Einträge fest, um sicherzustellen, dass die Daten aktuell sind und gleichzeitig eine hohe Leistung aufrechterhalten werden.

Vorteile

  1. Verbesserte Leistung: Reduziert die Belastung von APIs durch die Bereitstellung zwischengespeicherter Antworten für häufig aufgerufene Daten.
  2. Skalierbarkeit: Verwaltet effizient große Datenmengen und hohen Datenverkehr mit einem verteilten Caching-System.
  3. Flexibilität: Fein abgestimmte Kontrolle über das Caching, sodass Entwickler die Leistung optimieren können, ohne die Datengenauigkeit zu beeinträchtigen.

Link: Die zukunftsorientierte Komponente

Die Link-Komponente ist eine intelligente und leistungsstarke Lösung zum Vorladen von Ressourcen auf der Clientseite, die eine flüssigere und schnellere Navigation für Benutzer gewährleistet. Die Prefetching-Funktionalität wird aktiviert, wenn Sie mit der Maus über den Link fahren und so den Moment der Inaktivität des Benutzers nutzen, um die Zieldaten im Voraus anzufordern.

Wie funktioniert es?

  1. Bedingter Vorabruf: Das Prefetch-Attribut (standardmäßig aktiv) steuert, ob ein Vorabladen durchgeführt wird.

  2. Smart Cache: Ein Set wird verwendet, um die bereits vorinstallierten Links zu speichern und so redundante Aufrufe zu vermeiden.

  3. Mauseingabe: Wenn der Benutzer mit dem Cursor über den Link fährt, prüft die handleMouseEnter-Funktion, ob ein Vorladen erforderlich ist und initiiert in diesem Fall eine Abrufanforderung an das Ziel.

  4. Fehlersicher: Jeder Fehler in der Anfrage wird unterdrückt, um sicherzustellen, dass das Verhalten der Komponente nicht durch vorübergehende Netzwerkfehler beeinträchtigt wird.

// No servidor
class UserAPI extends Rpc {
  async searchUsers(query: string, filters: UserFilters) {
    // Validação com Zod
    const validated = searchSchema.parse({ query, filters });
    return this.db.users.search(validated);
  }
}

// No cliente
const UserSearch = () => {
  const { rpc } = app.useContext<App.Context>();

  // TypeScript sabe exatamente o que searchUsers aceita e retorna!
  const { data, loading, error, fetch: retry } = app.useFetch(
    async (ctx) => ctx.rpc.searchUsers('John', { age: '>18' })
  );
};
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Wenn der Benutzer mit der Maus über den Link „Über uns“ fährt, beginnt die Komponente mit dem Vorladen von Daten von der Seite „/about“, was einen fast sofortigen Übergang ermöglicht. Geniale Idee, oder? Aber ich habe es in der React.dev-Dokumentation gesehen.

app.useContext: Das Gateway zu Edge

app.useContext ist der grundlegende Hook von React Edge und bietet Zugriff auf den gesamten Worker-Kontext:

// pages/api/search.ts
export default async handler = (req, res) => {
  // Configurar CORS
  // Validar request
  // Tratar erros
  // Serializar resposta
  // ...100 linhas depois...
}

// app/search/page.tsx
'use client';
import { useEffect, useState } from 'react';

export default const SearchPage = () => {
  const [search, setSearch] = useState('');
  const [filters, setFilters] = useState({});
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    let timeout;
    const doSearch = async () => {
      setLoading(true);
      try {
        const res = await fetch('/api/search?' + new URLSearchParams({
          q: search,
          ...filters
        }));
        if (!res.ok) throw new Error('Search failed');
        setData(await res.json());
      } catch (err) {
        console.error(err);
      } finally {
        setLoading(false);
      }
    };

    timeout = setTimeout(doSearch, 300);
    return () => clearTimeout(timeout);
  }, [search, filters]);

  // ... resto do componente
}
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Hauptfunktionen von app.useContext

  • Routenverwaltung: Erhalten Sie mühelos Zugriff auf die entsprechende Route, ihre Parameter und Abfragezeichenfolgen.
  • RPC-Integration: Führen Sie getippte und sichere RPC-Aufrufe direkt vom Client aus ohne zusätzliche Konfiguration aus.
  • Gemeinsamer Store-Zugriff: Abrufen oder Festlegen von Werten im gemeinsam genutzten Worker-Client-Status mit vollständiger Kontrolle über die Sichtbarkeit (öffentlich/privat).
  • Universeller URL-Zugriff: Greifen Sie einfach auf die vollständige URL der aktuellen Anfrage zu, um dynamisches Rendering und Interaktionen zu ermöglichen.

Warum es mächtig ist

Der app.useContext-Hook schließt die Lücke zwischen dem Worker und dem Client. Sie können damit Funktionen erstellen, die auf gemeinsamem Status, sicherem Datenabruf und kontextbezogenem Rendering basieren, ohne sich wiederholenden Code. Dies vereinfacht komplexe Anwendungen, wodurch sie einfacher zu warten und schneller zu entwickeln sind.

app.useUrlState: Mit der URL synchronisierter Status

Der app.useUrlState-Hook sorgt dafür, dass der Status Ihrer Anwendung mit URL-Parametern synchronisiert wird, sodass Sie präzise steuern können, was in der URL enthalten ist, wie der Status serialisiert wird und wann er aktualisiert wird.

// Primeiro, definimos nossa API no servidor
class PropertiesAPI extends Rpc {
 async searchProperties(filters: PropertyFilters) {
   const results = await this.db.properties.search(filters);
   // Cache automático por 5 minutos
   return this.createResponse(results, {
     cache: { ttl: 300, tags: ['properties'] }
   });
 }

 async getPropertyDetails(ids: string[]) {
   return Promise.all(
     ids.map(id => this.db.properties.findById(id))
   );
 }
}

// Agora, no cliente, a mágica acontece
const PropertySearch = () => {
 const [filters, setFilters] = useState<PropertyFilters>({
   price: { min: 100000, max: 500000 },
   bedrooms: 2
 });

 // Busca reativa com debounce inteligente
 const { 
   data: searchResults,
   loading: searchLoading,
   error: searchError
 } = app.useFetch(
   async (ctx) => ctx.rpc.searchProperties(filters),
   {
     // Quando filters muda, refaz a busca
     deps: [filters],
     // Mas espera 300ms de 'silêncio' antes de buscar
     depsDebounce: {
       filters: 300
     }
   }
 );

 // Agora, vamos buscar os detalhes das propriedades encontradas
 const {
   data: propertyDetails,
   loading: detailsLoading,
   fetch: refreshDetails
 } = app.useFetch(
   async (ctx) => {
     if (!searchResults?.length) return null;

     // Isso parece fazer múltiplas chamadas, mas...
     return ctx.rpc.batch([
       // Na verdade, tudo é multiplexado em uma única requisição!
       ...searchResults.map(result => 
         ctx.rpc.getPropertyDetails(result.id)
       )
     ]);
   },
   {
     // Atualiza sempre que searchResults mudar
     deps: [searchResults]
   }
 );

 // Interface bonita e responsiva
 return (
   <div>
     <FiltersPanel 
       value={filters}
       onChange={setFilters}
       disabled={searchLoading}
     />

     {searchError && (
       <Alert status='error'>
         Erro na busca: {searchError.message}
       </Alert>
     )}

     <PropertyGrid
       items={propertyDetails || []}
       loading={detailsLoading}
       onRefresh={() => refreshDetails()}
     />
   </div>
 );
};
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Parameter

  1. Anfangszustand

    • Ein Objekt, das die Standardstruktur und -werte für seinen Zustand definiert.
  2. Optionen:

    • Debounce: Steuert, wie schnell die URL nach Statusänderungen aktualisiert wird.
    • kebabCase: Konvertiert Statusschlüssel bei der Serialisierung in eine URL in Kebab-Case.
    • omitKeys: Gibt Schlüssel an, die von der URL ausgeschlossen werden sollen.
    • omitValues: Werte, die, sofern vorhanden, den zugehörigen Schlüssel aus der URL ausschließen.
    • pickKeys: Beschränkt den Serialisierungsstatus so, dass er nur bestimmte Schlüssel enthält.
    • Präfix: Fügt allen Abfrageparametern ein Präfix hinzu.
    • URL: Die Basis-URL für die Synchronisierung, normalerweise abgeleitet vom Anwendungskontext.

Vorteile

  • SEO-freundlich: Stellt sicher, dass landesspezifische Ansichten in gemeinsam nutzbaren URLs widergespiegelt werden.
  • Aktualisierungen mit Debounce: Verhindert übermäßige Abfrageaktualisierungen für sich schnell ändernde Eingaben.
  • Saubere URLs: Optionen wie kebabCase und omitKeys sorgen dafür, dass Abfragezeichenfolgen lesbar bleiben.
  • Statushydrierung: Initialisiert automatisch den Status der URL beim Zusammenstellen der Komponente.
  • Funktioniert in allen Umgebungen: Unterstützt serverseitiges Rendering und clientseitiges Browsen.

Praktische Anwendungen

  • Filter für Einträge: Synchronisiert vom Benutzer angewendete Filter mit der URL.
  • Dynamische Ansichten: Stellt sicher, dass Kartenzoom, Mittelpunkte oder andere Einstellungen erhalten bleiben.
  • Benutzereinstellungen: Speichert ausgewählte Einstellungen zur Freigabe unter einer URL.

app.useStorageState: Persistenter Zustand

Der app.useStorageState-Hook ermöglicht es Ihnen, den Status im Browser mithilfe von localStorage oder sessionStorage mit vollständiger Tippunterstützung beizubehalten.

// No servidor
class UserAPI extends Rpc {
  async searchUsers(query: string, filters: UserFilters) {
    // Validação com Zod
    const validated = searchSchema.parse({ query, filters });
    return this.db.users.search(validated);
  }
}

// No cliente
const UserSearch = () => {
  const { rpc } = app.useContext<App.Context>();

  // TypeScript sabe exatamente o que searchUsers aceita e retorna!
  const { data, loading, error, fetch: retry } = app.useFetch(
    async (ctx) => ctx.rpc.searchUsers('John', { age: '>18' })
  );
};
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Persistenzoptionen

  • Entprellen: Steuert die Aufnahmefrequenz
  • Speicher: Wählen Sie zwischen localStorage und sessionStorage
  • omitKeys/pickKeys: Feine Kontrolle über persistente Daten

Leistung

  • Mit Debounce optimierte Updates
  • Automatische Serialisierung/Deserialisierung
  • Cache im Speicher

Häufige Anwendungsfälle

  • Suchverlauf
  • Favoritenliste
  • Benutzereinstellungen
  • Filterstatus
  • Temporärer Warenkorb
  • Formularentwürfe

app.useDebounce: Frequenzsteuerung

Reaktive Werte mühelos entprellen:

// pages/api/search.ts
export default async handler = (req, res) => {
  // Configurar CORS
  // Validar request
  // Tratar erros
  // Serializar resposta
  // ...100 linhas depois...
}

// app/search/page.tsx
'use client';
import { useEffect, useState } from 'react';

export default const SearchPage = () => {
  const [search, setSearch] = useState('');
  const [filters, setFilters] = useState({});
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    let timeout;
    const doSearch = async () => {
      setLoading(true);
      try {
        const res = await fetch('/api/search?' + new URLSearchParams({
          q: search,
          ...filters
        }));
        if (!res.ok) throw new Error('Search failed');
        setData(await res.json());
      } catch (err) {
        console.error(err);
      } finally {
        setLoading(false);
      }
    };

    timeout = setTimeout(doSearch, 300);
    return () => clearTimeout(timeout);
  }, [search, filters]);

  // ... resto do componente
}
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

app.useDistinct: Status ohne Duplikate

Behalten Sie Arrays mit eindeutigen Werten bei, indem Sie Folgendes eingeben:

app.useDistinct ist ein Hook, der darauf spezialisiert ist, zu erkennen, wann sich ein Wert tatsächlich geändert hat, mit Unterstützung für Tiefenvergleiche und Entprellen:

// No servidor
class UserAPI extends Rpc {
  async searchUsers(query: string, filters: UserFilters) {
    // Validação com Zod
    const validated = searchSchema.parse({ query, filters });
    return this.db.users.search(validated);
  }
}

// No cliente
const UserSearch = () => {
  const { rpc } = app.useContext<App.Context>();

  // TypeScript sabe exatamente o que searchUsers aceita e retorna!
  const { data, loading, error, fetch: retry } = app.useFetch(
    async (ctx) => ctx.rpc.searchUsers('John', { age: '>18' })
  );
};
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Hauptmerkmale

  1. Erkennung eindeutiger Werte:
    • Überwacht aktuelle und vorherige Werte
    • Erkennt anhand Ihrer Kriterien automatisch, ob eine Änderung signifikant ist
  2. Tiefer Vergleich:
    • Ermöglicht tiefgreifende Gleichheitsprüfungen für komplexe Objekte
  3. Personalisierter Vergleich:
    • Unterstützt benutzerdefinierte Funktionen, um zu definieren, was eine „eindeutige“ Änderung darstellt
  4. Entprellt:
    • Reduziert unnötige Aktualisierungen, wenn Änderungen zu häufig auftreten

Vorteile

  • API identisch mit useState: Einfache Integration in bestehende Komponenten.
  • Optimierte Leistung: Verhindert unnötiges erneutes Abrufen oder Neuberechnungen, wenn sich der Wert nicht wesentlich geändert hat. Verbesserte UX: Verhindert übermäßig reaktive UI-Updates, was zu reibungsloseren Interaktionen führt.
  • Vereinfachte Logik: Eliminiert manuelle Prüfungen auf Gleichheit oder Duplikate in der Statusverwaltung.

React Edge-Hooks wurden so konzipiert, dass sie harmonisch funktionieren und ein flüssiges und typisiertes Entwicklungserlebnis bieten. Durch die Kombination können Sie komplexe und reaktive Schnittstellen mit viel weniger Code erstellen.

Die React Edge CLI: Leistung immer zur Hand

Die React Edge CLI wurde entwickelt, um Entwicklern das Leben zu erleichtern, indem sie wichtige Tools in einer einzigen, intuitiven Oberfläche zusammenführt. Unabhängig davon, ob Sie Anfänger oder Experte sind, stellt die CLI sicher, dass Sie Projekte effizient und problemlos konfigurieren, entwickeln, testen und bereitstellen können.

Hauptfunktionen

Modulare und flexible Befehle:

  • Build: Erstellt sowohl die App als auch den Worker mit Optionen zum Angeben von Entwicklungs- oder Produktionsumgebungen und -modi.
  • dev: Startet lokale oder Remote-Entwicklungsserver, sodass Sie separat an der App oder dem Worker arbeiten können.
  • Bereitstellung: Führt schnelle und effiziente Bereitstellungen mit der kombinierten Leistung von Cloudflare Workers und Cloudflare R2 durch und gewährleistet so Leistung und Skalierbarkeit in der Edge-Infrastruktur.
  • Protokolle: Überwachen Sie Arbeiterprotokolle direkt im Terminal.
  • lint: Automatisiert die Ausführung von Prettier und ESLint, mit Unterstützung für automatische Korrekturen.
  • Test: Führt Tests mit optionaler Abdeckung mit Vitest durch.
  • Typprüfung: Validiert die TypeScript-Eingabe im Projekt.

Produktionsanwendungsfälle

Ich bin stolz, Ihnen mitteilen zu können, dass die erste Produktionsanwendung mit React Edge jetzt funktioniert! Hierbei handelt es sich um ein brasilianisches Immobilienunternehmen, Lopes Imóveis, das bereits die gesamte Leistung und Flexibilität des Frameworks nutzt.

Auf der Website der Immobilienagentur werden Immobilien in den Cache geladen, um die Suche zu optimieren und den Benutzern ein flüssigeres Erlebnis zu bieten. Da es sich um eine äußerst dynamische Website handelt, verwendet der Routen-Cache eine TTL von nur 10 Sekunden, kombiniert mit der Stale-While-Revalidate-Strategie. Dadurch wird sichergestellt, dass die Site auch bei erneuten Validierungen im Hintergrund aktuelle Daten mit außergewöhnlicher Leistung liefert.

Darüber hinaus werden Empfehlungen für ähnliche Eigenschaften effizient und gelegentlich im Hintergrund berechnet und mithilfe des in RPC integrierten Cache-Systems direkt im Cache von Cloudflare gespeichert. Dieser Ansatz verkürzt die Reaktionszeit bei nachfolgenden Anfragen und macht Abfrageempfehlungen nahezu augenblicklich. Darüber hinaus werden alle Bilder auf Cloudflare R2 gespeichert und bieten so skalierbaren und verteilten Speicher, ohne auf externe Anbieter angewiesen zu sein.

De Next.js a React Edge com Cloudflare Workers: Uma História de Libertação
De Next.js a React Edge com Cloudflare Workers: Uma História de Libertação

Und bald werden wir auch ein gigantisches automatisiertes Marketingprojekt für Easy Auth starten, das das Potenzial dieser Technologie weiter demonstriert.

Abschluss

Und so, liebe Leser, sind wir am Ende dieses Abenteuers durch das React Edge-Universum angelangt! Ich weiß, dass es immer noch eine Menge unglaublicher Dinge zu erforschen gibt, wie zum Beispiel die einfachsten Authentifizierungen wie Basic und Bearer und andere kleine Geheimnisse, die das tägliche Leben eines Entwicklers viel glücklicher machen. Aber beruhige dich! Die Idee besteht darin, in Zukunft ausführlichere Artikel zu veröffentlichen, die sich mit den einzelnen Funktionen befassen.

Und, Spoiler: Bald wird React Edge Open Source sein und ordnungsgemäß dokumentiert sein! Entwicklung, Arbeit, Schreiben und ein wenig soziales Leben unter einen Hut zu bringen, ist nicht einfach, aber die Aufregung, dieses Wunder in Aktion zu sehen, insbesondere mit der absurden Geschwindigkeit, die die Infrastruktur von Cloudflare bietet, ist der Treibstoff, der mich bewegt. Halten Sie also Ihre Ängste zurück, denn das Beste kommt noch! ?

Wenn Sie in der Zwischenzeit sofort mit der Erkundung und dem Testen beginnen möchten, ist das Paket jetzt auf NPM verfügbar: React Edge auf NPM.

Meine E-Mail lautet feliperohdee@gmail.com und ich bin immer offen für Feedback, das ist erst der Anfang dieser Reise, für Vorschläge und konstruktive Kritik. Wenn Ihnen das, was Sie gelesen haben, gefallen hat, teilen Sie es mit Ihren Freunden und Kollegen und halten Sie Ausschau nach neuen Dingen. Vielen Dank, dass Sie mir bis hierher gefolgt sind, und bis zum nächsten Mal! ???

Das obige ist der detaillierte Inhalt vonVon Next.js zu React Edge mit Cloudflare Workers: Eine Befreiungsgeschichte. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:dev.to
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage