Heim  >  Artikel  >  Web-Frontend  >  Erstellen einer CRUD-App mit React-Form, Zod, React Data Grid, React-Query und JSON-Server

Erstellen einer CRUD-App mit React-Form, Zod, React Data Grid, React-Query und JSON-Server

Linda Hamilton
Linda HamiltonOriginal
2024-11-24 19:14:10548Durchsuche

Ziel :

Unser Ziel ist die Entwicklung einer React CRUD-Anwendung.

Building CRUD App with react-form, zod, react data grid, react-query and json-server

Unser Stapel:

  • Reaktionsform
  • zod
  • ag-grid-react
  • react-query
  • json-server

Setup-Umgebung:

Erstellen Sie ein Reaktionsprojekt mit vite:

npm create vite@latest crud-react -- --template react-ts

Abhängigkeiten installieren:

npm install react-hook-form zod @hookform/resolvers ag-grid-react react-query axios

Server erstellen und starten:

Objekt-(Produkt-)Struktur:

{
    "id": "w38y",
    "name": "Vitamin C Tablets",
    "price": 19.99,
    "expiryDate": "2025-01-01",
    "emailSupplier": "contact@healthplus.com"
}

Erstellen Sie eine Datei, die Beispieldaten in /db/db.json enthält:

{
  "products": [
    {
      "id": "w38y",
      "name": "Vitamin C Tablets",
      "price": 19.99,
      "expiryDate": "2025-01-01",
      "emailSupplier": "contact@healthplus.com"
    },
    {
      "id": "a99x",
      "name": "Omega-3 Fish Oil",
      "price": 30.99,
      "expiryDate": "2024-11-15",
      "emailSupplier": "support@nutricore.com"
    },
    {
      "id": "x82j",
      "name": "Calcium + Vitamin D",
      "price": 15.5,
      "expiryDate": "2026-06-01",
      "emailSupplier": "orders@welllifelabs.com"
    },
    {
      "id": "a40i",
      "name": "Zinc Lozenges",
      "price": 12.99,
      "expiryDate": "2024-09-30",
      "emailSupplier": "sales@herbalessentials.com"
    },
    {
      "id": "c52f",
      "name": "Probiotic Capsules",
      "price": 25.75,
      "expiryDate": "2025-03-20",
      "emailSupplier": "info@guthealthlabs.com"
    }
  ]
}

JSON-Server starten:

npx json-server db/db.json

Reaktionsabfrage einrichten:

Aktualisieren Sie /src/App.tsx:

import { QueryClient, QueryClientProvider } from "react-query";

const queryClient = new QueryClient();

function App() {
  return (
    <QueryClientProvider client={queryClient}>
    </QueryClientProvider>
  );
}

export default App;

Erstellen Sie /src/types.ts:

export type FormData = {
  name: string;
  price: number;
  expiryDate: string;
  emailSupplier: string;
};

export type FormFieldNames = "name" | "price" | "expiryDate" | "emailSupplier";  

export type Product = {
  id: string;
  name: string;
  price: number;
  expiryDate: string;
  emailSupplier: string;
};

Erstellen Sie /src/server/productQuery.ts:

import { useMutation, useQuery, useQueryClient } from "react-query";
import { FormData, Product } from "../types";
import axios from "axios";

const URL = "http://localhost:3000";
const PRODUCTS = "products";

export const save = async (product: FormData) =>
  axios.post(`${URL}/${PRODUCTS}`, product);

export const useSave = () => {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: (newProduct: FormData) => save(newProduct),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: [PRODUCTS] });
    },
  });
};

export const fetch = async () => {
  const result = await axios.get(`${URL}/${PRODUCTS}`);
  return result.data;
};

export const useProducts = () =>
  useQuery<Product[]>({
    queryKey: [PRODUCTS],
    queryFn: fetch,
  });

const remove = async (id: string) => {
  await axios.delete(`${URL}/${PRODUCTS}/${id}`);
};

export const useRemove = () => {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: (id: string) => remove(id),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: [PRODUCTS] });
    },
  });
};

export const update = async (product: Product) =>
  axios.put(`${URL}/${PRODUCTS}/${product.id}`, product);

export const useUpdate = () => {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: (product: Product) => update(product),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: [PRODUCTS] });
    },
  });
};

Formular erstellen:

Aktualisieren Sie /src/types.ts:

import { z, ZodType } from "zod";

export type FormData = {
  name: string;
  price: number;
  expiryDate: string;
  emailSupplier: string;
};

export type FormFieldNames = "name" | "price" | "expiryDate" | "emailSupplier";

export const ProductSchema: ZodType<FormData> = z.object({
  name: z.string().min(3),
  price: z.number().min(1).max(1000),
  expiryDate: z
    .string()
    .refine(
      (date) => new Date(date) > new Date(),
      "Expiry Date must be superior than current date",
    ),
  emailSupplier: z.string().email(),
});



export type Product = {
  id: string;
  name: string;
  price: number;
  expiryDate: string;
  emailSupplier: string;
};

Erstellen Sie /src/components/form/FormField.tsx:

import { FieldError, UseFormRegister } from "react-hook-form";
import { FormData, FormFieldNames } from "../../types";

type FormFieldProps = {
  type: string;
  placeholder: string;
  name: FormFieldNames;
  register: UseFormRegister<FormData>;
  error: FieldError | undefined;
  valueAsNumber?: boolean;
  step?: number | string;
};

const FormField = ({
  type,
  placeholder,
  name,
  register,
  error,
  valueAsNumber,
  step,
}: FormFieldProps) => (
  <>
    <input
      type={type}
      placeholder={placeholder}
      step={step}
      {...register(name, { valueAsNumber })}
    />
    {error && <span> {error.message} </span>}
  </>
);

export default FormField;

Erstellen Sie /src/components/form/Form.tsx:

import { useForm } from "react-hook-form";
import FormField from "./FormField";
import { FormData, ProductSchema } from "../../types";
import { zodResolver } from "@hookform/resolvers/zod";
import { useSave } from "../../server/productQuery";

const Form = () => {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<FormData>({
    resolver: zodResolver(ProductSchema),
  });

  const mutation = useSave();

  const onSubmit = (data: FormData) => {
    mutation.mutate(data);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <div>
        <FormField
          type="text"
          placeholder="Name"
          name="name"
          register={register}
          error={errors.name}
        />
        <FormField
          type="number"
          placeholder="Price"
          name="price"
          step="0.01"
          register={register}
          error={errors.price}
          valueAsNumber
        />
        <FormField
          type="date"
          placeholder="Expiry Date"
          name="expiryDate"
          register={register}
          error={errors.expiryDate}
        />

        <FormField
          type="email"
          placeholder="Email"
          name="emailSupplier"
          register={register}
          error={errors.emailSupplier}
        />
        <button type="submit">Add</button>
      </div>
    </form>
  );
};

export default Form;

Tabelle erstellen:

Erstellen Sie /src/components/table/Products.tsx:

import { useMemo } from "react";
import { Product } from "../../types";
import { useProducts, useRemove, useUpdate } from "../../server/productQuery";

import { AgGridReact } from "ag-grid-react";
import { ColDef, ColGroupDef } from "ag-grid-community";
import "ag-grid-community/styles/ag-grid.css";
import "ag-grid-community/styles/ag-theme-quartz.css";

const Products = () => {
  const { data: products } = useProducts();
  const removeMutation = useRemove();
  const updateMutation = useUpdate();

  const columns = useMemo<(ColDef | ColGroupDef<Product>)[]>(
    () => [
      { field: "id", editable: false },
      { field: "name", editable: true },
      { field: "price", editable: true },
      { field: "expiryDate", editable: true },
      { field: "emailSupplier", editable: true },
      {
        field: "delete",
        sortable: false,
        editable: false,
        cellRenderer: (params: { data: Product }) => (
          <button onClick={() => removeMutation.mutate(params.data.id)}>
            Delete
          </button>
        ),
      },
    ],
    [],
  );

  return (
    <div className="ag-theme-quartz">



<p>Update /src/App.tsx :<br>
</p>

<pre class="brush:php;toolbar:false">import { QueryClient, QueryClientProvider } from "react-query";
import Form from "./components/form/Form";
import Products from "./components/table/Products";

const queryClient = new QueryClient();

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <Form />
      <Products />
    </QueryClientProvider>
  );
}

export default App;

Git-Repository:

https://github.com/TesMae/crud-react

Vielen Dank fürs Mitmachen!

Das obige ist der detaillierte Inhalt vonErstellen einer CRUD-App mit React-Form, Zod, React Data Grid, React-Query und JSON-Server. 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