Heim  >  Artikel  >  Web-Frontend  >  Reagieren – Serveraktionen

Reagieren – Serveraktionen

WBOY
WBOYOriginal
2024-08-09 07:34:12951Durchsuche

Reagieren Sie auf Aktionen.

React hat neue Formularaktionen und zugehörige Hooks eingeführt, um native Formulare zu verbessern und die Client-Server-Kommunikation zu optimieren. Diese Funktionen ermöglichen es Entwicklern, Formularübermittlungen effektiver zu bearbeiten und so sowohl die Benutzererfahrung als auch die Wartbarkeit des Codes zu verbessern. Eine ausführliche Untersuchung der React-Formularaktionen finden Sie in meinem ausführlichen Beitrag zu meinem Beitrag über React-Formularaktionen.

Serveraktionen

Mit React 18 wurde die Serverkomponenten-Funktion eingeführt. Bei Serverkomponenten handelt es sich nicht um Server-Side Rendering (SSR). Serverkomponenten werden sowohl zur Laufzeit als auch zur Buildzeit ausschließlich auf dem Server ausgeführt. Diese Komponenten können auf serverseitige Ressourcen wie Datenbanken und das Dateisystem zugreifen, sind jedoch nicht in der Lage, clientseitige Aktionen wie Ereignis-Listener oder Hooks auszuführen.

Voraussetzungen

Um die Fähigkeiten von Serverkomponenten und Serveraktionen zu demonstrieren, verwenden wir Next.js und Prisma.

Next.js ist ein React-Framework zum Erstellen von Full-Stack-Webanwendungen. Sie verwenden React Components zum Erstellen von Benutzeroberflächen und Next.js für zusätzliche Funktionen und Optimierungen. Unter der Haube abstrahiert und konfiguriert Next.js auch die für React benötigten Tools wie Bündelung, Kompilierung und mehr und konfiguriert sie automatisch. Dadurch können Sie sich auf die Erstellung Ihrer Anwendung konzentrieren, anstatt Zeit mit der Konfiguration zu verbringen. Erfahren Sie mehr

Prisma ist ein ORM, das den Datenbankzugriff und -betrieb vereinfacht und es Ihnen ermöglicht, Daten abzufragen und zu bearbeiten, ohne SQL schreiben zu müssen. Erfahren Sie mehr

Ersteinrichtung
Beginnen Sie mit der Erstellung einer neuen Next.js-Anwendung:
Garn erstellt Next-App-Serverbeispiel

Ihre anfängliche Ordnerstruktur sieht folgendermaßen aus:

React - Server Actions

Upgrade auf die Canary-Version, um auf React 19-Funktionen zuzugreifen, einschließlich Serveraktionen:

yarn add next@rc react@rc react-dom@rc

Prisma installieren

yarn add prisma

Prisma-Konfiguration
Erstellen Sie eine Prisma-Schemadatei unter src/lib/prisma/schema.prisma:

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "sqlite"
  url      = "file:./dev.db"
}

model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
  name  String?
  age Int
}

Zu Demonstrationszwecken verwenden wir SQLite. Für die Produktion sollten Sie eine robustere Datenbank verwenden.

Fügen Sie als Nächstes eine Prisma-Client-Datei unter src/lib/prisma/prisma.ts hinzu

// ts-ignore 7017 is used to ignore the error that the global object is not
// defined in the global scope. This is because the global object is only
// defined in the global scope in Node.js and not in the browser.

import { PrismaClient } from '@prisma/client'

// PrismaClient is attached to the `global` object in development to prevent
// exhausting your database connection limit.
//
// Learn more:
// https://pris.ly/d/help/next-js-best-practices

const globalForPrisma = global as unknown as { prisma: PrismaClient }

export const prisma = globalForPrisma.prisma || new PrismaClient()

if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma

export default prisma

Konfigurieren Sie Prisma in package.json:

{
  //other settings
  "prisma": {
    "schema": "src/lib/prisma/schema.prisma",
    "seed": "ts-node src/lib/prisma/seed.ts"
  }
}

Und aktualisieren Sie die TypeScript-Einstellungen in tsconfig.json:

{
  //Other settings here...

  "ts-node": {
    // these options are overrides used only by ts-node
    // same as the --compilerOptions flag and the 
    // TS_NODE_COMPILER_OPTIONS environment variable
    "compilerOptions": {
      "module": "commonjs"
    }
  }
}

ts-node global installieren:

yarn global add ts-node

Seeding der Anfangsdaten
Fügen Sie eine Seed-Datei unter src/lib/prisma/seed.ts hinzu, um die Anfangsdaten zu füllen:

import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
async function main() {
  await prisma.user.create({
    email: "anto@prisma.io",
    name: "Anto",
    age: 35,
  });
  await prisma.user.create({
    email: "vinish@prisma.io",
    name: "Vinish",
    age: 32,
  });
}
main()
  .then(async () => {
    await prisma.$disconnect();
  })
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    process.exit(1);
  });

Prisma-Client installieren

yarn add @prisma/client

Führen Sie den Migrationsbefehl aus:

yarn prisma migrate dev --name init

Wenn die Seed-Daten nicht wiedergegeben werden, fügen Sie sie manuell hinzu:

yarn prisma db seed

Großartig! Da die Installationen fertig sind, können Sie eine Aktionsdatei erstellen, die Datenbankoperationen ausführt.

Serveraktionen erstellen
Serveraktionen sind eine leistungsstarke Funktion, die eine nahtlose Client-Server-Kommunikation ermöglicht. Erstellen wir eine Datei für Datenbankoperationen unter src/actions/user.ts:

"use server";
import prisma from '@/lib/prisma/prisma'
import { revalidatePath } from "next/cache";

// export type for user
export type User = {
  id: number;
  name: string | null;
  email: string;
  age: number;
};


export async function createUser(user: any) {
  const resp = await prisma.user.create({ data: user });
  console.log("server Response");
  revalidatePath("/");
  return resp;
}

export async function getUsers() {
  return await prisma.user.findMany();
}

export async function deleteUser(id: number) {
  await prisma.user.delete({
    where: {
      id: id,
    },
  });
  revalidatePath("/");
}

Implementierung von Serverkomponenten

Lassen Sie uns eine React-Serverkomponente erstellen, um Daten aus der Datenbank zu lesen und darzustellen. Erstellen Sie src/app/serverexample/page.tsx:

import UserList from "./Users";
import "./App.css"

export default async function ServerPage() {
  return (
    <div classname="app">
      <header classname="App-header">
        <userlist></userlist>
      </header>
    </div>
  );
}

Fügen Sie etwas Stil in src/app/serverexample/App.css hinzu

.App {
  text-align: center;
}

.App-logo {
  height: 40vmin;
  pointer-events: none;
}

.App-header {
  background-color: #282c34;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: calc(10px + 2vmin);
  color: white;
}

input {
  color: #000;
}

.App-link {
  color: #61dafb;
}

Erstellen Sie Komponenten zum Abrufen und Rendern der Benutzerliste:
src/app/serverexample/UserList.tsx

import { getUsers } from "@/actions/user";
import { UserDetail } from "./UserDetail";

export default async function UserList() {
  //Api call to fetch User details
  const users = await getUsers();

  return (
    <div classname="grid grid-cols-3 gap-5">
      {users.length ? (
        users.map((user) => <userdetail user="{user}"></userdetail>)
      ) : (
        <div classname="col-span3 opacity-60 text-sm text-center">
          No User found
        </div>
      )}
    </div>
  );
}

src/app/serverexample/UserDetail.tsx

export function UserDetail({ user }) {
  return (
    <div classname="flex items-center gap-4 border border-gray-600 py-1 px-4">
      <img classname="w-10 h-10 rounded-full" src="https://api.dicebear.com/9.x/personas/svg?seed=Shadow" alt="Reagieren – Serveraktionen">
      <div classname="font-medium text-base dark:text-white">
        <div>{user.name}</div>
        <div classname="text-sm text-gray-500 dark:text-gray-400">
          {user.email}
        </div>
      </div>
    </div>
  );
}

Führen Sie den Entwicklungsserver aus:

yarn dev

Navigieren Sie zu http://localhost:3000/serverexample, um die gerenderte Benutzerliste anzuzeigen:
React - Server Actions

Standardmäßig sind Komponenten in Next.js Serverkomponenten, es sei denn, Sie geben die Anweisung „Client verwenden“ an. Beachten Sie zwei wichtige Punkte:

  1. Asynchrone Komponentendefinition: Serverkomponenten können asynchron sein, da sie nicht erneut gerendert werden und nur einmal generiert werden.
  2. Datenabruf: Die Zeile const users = waiting getUsers(); ruft Daten vom Server ab und rendert sie zur Laufzeit.

Erkunden von Serveraktionen

Serveraktionen ermöglichen eine nahtlose Client-Server-Kommunikation. Fügen wir ein Formular hinzu, um neue Benutzer zu erstellen.

Erstellen Sie eine neue Datei unter src/app/serverexample/AddUser.tsx:

"use client";

import "./app.css";
import { useActionState } from "react";
import { createUser } from "../../actions/user";

const initialState = {
  error: undefined,
};

export default function AddUser() {
  const submitHandler = async (_previousState: object, formData: FormData) => {
    try {
      // This is the Server Action method that transfers the control 
      // Back to the server to do DB operations and get back the result.
      const response = await createUser({
        name: formData.get("name") as string,
        email: formData.get("email") as string,
        age: parseInt(formData.get("age") as string),
      });
      return { response };
    } catch (error) {
      return { error };
    }
  };
  const [state, submitAction, isPending] = useActionState(
    submitHandler,
    initialState
  );

  return (
    <div classname="mt-10">
      <h4 classname="text-center">Add new User</h4>{" "}
      <form action="%7BsubmitAction%7D" classname="text-base">
        <div classname="mt-6 text-right">
          Name:{" "}
          <input classname="ml-2" required name="name" type="text" placeholder="Name">
        </div>
        <div classname="mt-6 text-right">
          Email:{" "}
          <input classname="ml-2" name="email" type="email" placeholder="Email">
        </div>
        <div classname="mt-6 text-right">
          Age:{" "}
          <input classname="ml-2" name="age" type="text" placeholder="Age">
        </div>
        <div classname="mt-6 text-right">
          <button disabled classname="bg-green-600 text-white px-5 py-1 text-base disabled:opacity-30">
            {isPending ? "Adding" : "Add User"}
          </button>
        </div>

        {(state?.error as string) && <p>{state.error as string}</p>}
      </form>
    </div>
  );
}

Aktualisieren Sie src/app/serverexample/page.tsx, um die AddUser-Komponente einzuschließen:

import UserList from "./UserList";
// Import new line
import AddUser from "./AddUser";
import "./App.css"

export default async function ServerPage() {
  return (
    <div classname="app">
      <header classname="App-header">
        <userlist></userlist>
        {/* insert Add User here */}
        <adduser></adduser>
      </header>
    </div>
  );
}

Wenn Sie die Anwendung ausführen, können Sie jetzt neue Benutzer über das Formular hinzufügen, wobei die serverseitige Verarbeitung nahtlos abgewickelt wird.
React - Server Actions

The AddUser Component and Seamless Client-Server Interaction

The AddUser component is at the heart of this example, showcasing how React Server Actions can revolutionize the way we handle client-server interactions. This component renders a form for adding new users and leverages the useActionState hook to create a smooth and seamless bridge between the client-side interface and server-side operations.

How It Works

  1. Form Rendering and Data Handling:
  • The AddUser component provides a form where users can input their name, email, and age.
  • Upon form submission, the data is captured and prepared to be sent to the server.
  1. useActionState Hook:
  • The useActionState hook is a crucial part of this setup. It simplifies the complexity of managing client-side state and server-side actions by abstracting them into a unified interface.
  • This hook accepts an asynchronous handler function, which processes the form data and then calls a Server Action method.
  • The brilliance of this approach lies in its abstraction: it feels as though you’re invoking a regular function within the same file, even though it actually triggers a server-side operation.
  1. Server Action Method:
  • The createUser function, defined as a Server Action, executes on the server side. It takes the user data from the form, performs the necessary database operations via Prisma, and returns the result.
  • This server-side method is crucial for maintaining a clean separation between the client and server, while still enabling them to communicate effectively.
  1. Seamless Integration:

From the perspective of a developer working on the client side, it appears as if the form submission is handled locally. However, the heavy lifting such as database manipulation occurs on the server.
The useActionState hook encapsulates this process, managing the state transitions and handling errors, while maintaining an intuitive API for developers.

Server Actions Without Forms

So that's with forms, now lets test an example without forms.
update src/app/serverexample/UserDetail.tsx

"use client";
import { deleteUser } from "@/actions/user";
import { useTransition } from "react";

export function UserDetail({ user }) {
  const [pending, startTransition] = useTransition();

  const handleDelete = () => {
    startTransition(() => {
      deleteUser(user.id);
    });
  };

  return (
    <div classname="flex items-center gap-4 border border-gray-600 py-1 px-4">
      {pending ? (
        <p>Deleting...</p>
      ) : (
        
          <img classname="w-10 h-10 rounded-full" src="https://api.dicebear.com/9.x/personas/svg?seed=Shadow" alt="Reagieren – Serveraktionen">
          <div classname="font-medium text-base dark:text-white">
            <div>{user.name}</div>
            <div classname="text-sm text-gray-500 dark:text-gray-400">
              {user.email}
            </div>
          </div>
          <button classname="ml-auto" onclick="{handleDelete}">
            <img classname="w-4 h-4" src="/delete.png" alt="">
          </button>
        >
      )}
    </div>
  );
}

Key Points:

  • Server Action: deleteUser(user.id) is a server action that removes the user from the database. This operation is triggered without any form submission.
  • useTransition: This hook allows you to manage the asynchronous state of the deletion process, showing a "Deleting..." message while the operation is in progress.
  • User Interface: The component maintains a clean UI, dynamically updating based on the action status.

Now, you can seamlessly delete a user within the application:
React - Server Actions

Conclusion

This approach is transformative because it abstracts away the complexities of client-server communication. Traditionally, such interactions would require handling API endpoints, managing asynchronous requests, and carefully coordinating client-side state with server responses. With React Server Actions and the useActionState hook, this complexity is reduced, allowing developers to focus more on building features rather than worrying about the underlying infrastructure.

By using this pattern, you gain:

  • Cleaner Code: The client-side code remains simple and focused, without the need for explicit API calls.
  • Improved Developer Experience: Server-side operations are seamlessly integrated, reducing cognitive load and potential for errors.
  • Enhanced Performance: Server Actions are optimized for performance, reducing unnecessary client-server round trips and ensuring that server-side resources are used efficiently.

You can find the full code in the repository

Das obige ist der detaillierte Inhalt vonReagieren – Serveraktionen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
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
Vorheriger Artikel:ServicemitarbeiterNächster Artikel:Servicemitarbeiter