React a introduit de nouvelles actions de formulaire et des hooks associés pour améliorer les formulaires natifs et rationaliser la communication client-serveur. Ces fonctionnalités permettent aux développeurs de gérer plus efficacement les soumissions de formulaires, améliorant ainsi à la fois l'expérience utilisateur et la maintenabilité du code. Pour une exploration approfondie des actions de formulaire React, vous pouvez vous référer à mon article détaillé sur mon article sur les actions de formulaire React.
Avec React 18, la fonctionnalité Composants Serveur a été introduite. Les composants du serveur ne sont pas rendus côté serveur (SSR), les composants du serveur sont exécutés exclusivement sur le serveur pendant l'exécution et la construction. Ces composants peuvent accéder aux ressources côté serveur, telles que les bases de données et le système de fichiers, mais ils ne sont pas capables d'effectuer des actions côté client comme les écouteurs d'événements ou les hooks.
Pour démontrer les capacités des composants serveur et des actions serveur, nous utiliserons Next.js et Prisma.
Next.js est un framework React permettant de créer des applications Web full-stack. Vous utilisez les composants React pour créer des interfaces utilisateur et Next.js pour des fonctionnalités et des optimisations supplémentaires. Sous le capot, Next.js résume et configure automatiquement les outils nécessaires à React, comme le regroupement, la compilation, etc. Cela vous permet de vous concentrer sur la création de votre application au lieu de passer du temps sur la configuration. en savoir plus
Prisma est un ORM qui simplifie l'accès et les opérations aux bases de données, vous permettant d'interroger et de manipuler des données sans écrire de SQL. En savoir plus
Configuration initiale
Commencez par créer une nouvelle application Next.js :
Yarn Create Next-App Server-Exemple
Votre structure de dossiers initiale ressemblera à ceci :
Mettez à niveau vers la version Canary pour accéder aux fonctionnalités de React 19, y compris les actions du serveur :
yarn add next@rc react@rc react-dom@rc
installer Prisma
yarn add prisma
Configuration Prisma
Créez un fichier de schéma Prisma sur 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 }
À des fins de démonstration, nous utilisons SQLite. Pour la production, vous devez utiliser une base de données plus robuste.
Ensuite, ajoutez un fichier client Prisma à src/lib/prisma/prisma.ts
// 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
Configurez Prisma dans package.json :
{ //other settings "prisma": { "schema": "src/lib/prisma/schema.prisma", "seed": "ts-node src/lib/prisma/seed.ts" } }
Et mettez à jour les paramètres TypeScript dans 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" } } }
Installez ts-node globalement :
yarn global add ts-node
Amorçage des données initiales
Ajoutez un fichier de départ dans src/lib/prisma/seed.ts pour remplir les données initiales :
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); });
Installer le client Prisma
yarn add @prisma/client
Exécutez la commande de migration :
yarn prisma migrate dev --name init
Si les données de départ ne sont pas reflétées, ajoutez-les manuellement :
yarn prisma db seed
Super ! Puisque les installations sont prêtes, vous pouvez créer un fichier d'actions qui effectue des opérations de base de données.
Création d'actions de serveur
Les actions serveur sont une fonctionnalité puissante qui permet une intercommunication client-serveur transparente. Créons un fichier pour les opérations de base de données sur 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("/"); }
Créons un composant serveur React pour lire et restituer les données de la base de données. Créez 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> ); }
Ajoutez du style dans src/app/serverexample/App.css
.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; }
Créez des composants pour récupérer et afficher la liste des utilisateurs :
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="Réagir – Actions du serveur"> <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> ); }
Exécutez le serveur de développement :
yarn dev
Accédez à http://localhost:3000/serverexample pour voir la liste des utilisateurs rendue :
Par défaut, les composants de Next.js sont des composants serveur sauf si vous spécifiez la directive "use client". Notez deux points importants :
Les actions du serveur permettent une intercommunication client-serveur transparente. Ajoutons un formulaire pour créer de nouveaux utilisateurs.
Créez un nouveau fichier sur 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> ); }
Mettez à jour src/app/serverexample/page.tsx pour inclure le composant AddUser :
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> ); }
L'exécution de l'application vous permettra désormais d'ajouter de nouveaux utilisateurs via le formulaire, avec un traitement côté serveur géré de manière transparente.
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
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.
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="Réagir – Actions du serveur"> <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:
Now, you can seamlessly delete a user within the application:
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:
You can find the full code in the repository
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!