Heim >Web-Frontend >js-Tutorial >Erstellen einer Datentabelle mit optimistischen Aktualisierungen

Erstellen einer Datentabelle mit optimistischen Aktualisierungen

DDD
DDDOriginal
2024-11-04 07:28:011032Durchsuche

Einführung

Heute erzähle ich, wie ich mit modernen React-Mustern ein ausgefeiltes Lebensmitteldatenbank-Managementsystem aufgebaut habe. Wir werden uns auf die Erstellung einer reaktionsfähigen Datentabelle mit nahtlosen optimistischen Aktualisierungen konzentrieren und dabei die Leistungsfähigkeit von TanStack Query (ehemals React Query) mit der Komponentenbibliothek von Mantine kombinieren.

Projektübersicht

Anforderungen

  • Lebensmittel in einer Datentabelle anzeigen
  • Fügen Sie neue Artikel mit sofortigem Feedback hinzu
  • Behandeln Sie Lade- und Fehlerzustände ordnungsgemäß
  • Sorgen Sie für reibungslose, optimistische Updates

Tech-Stack

  • TanStack Query: Serverstatusverwaltung
  • Mantine UI: Komponentenbibliothek und Formularverwaltung
  • Mantine React Table: Erweiterte Tabellenfunktionalität
  • Wretch: Saubere API-Aufrufe
  • TypeScript: Typsicherheit

Implementierungsleitfaden

1. Gründung der Stiftung

Zuerst definieren wir unsere Typen und API-Konfiguration:

// Types
export type GetAllFoods = {
  id: number;
  name: string;
  category: string;
};

export type CreateNewFoodType = Pick<
  GetAllFoods,
  | 'name'
  | 'category'
>;

// API Configuration
export const API = wretch('<http://localhost:9999>').options({
  credentials: 'include',
  mode: 'cors',
  headers: {
    'Content-Type': 'application/json',
    Accept: 'application/json',
  },
});

// TANSTACK QUERY 
export const getFoodOptions = () => {
  return queryOptions({
    queryKey: ['all-foods'],
    queryFn: async () => {
      try {
        return await API.get('/foods')
          .unauthorized(() => {
            console.log('Unauthorized');
          })
          .json<Array<GetAllFoods>>();
      } catch (e) {
        console.log({ e });
        throw e;
      }
    },
  });
};

export const useGetAllFoods = () => {
  return useQuery({
    ...getFoodOptions(),
  });
};

2. Erstellen der Datentabelle

Die Tabellenkomponente, die Mantine React Table verwendet:

const FoodsView = () => {
  const { data } = useGetAllFoods();

  const columns = useMemo<MRT_ColumnDef<GetAllFoods>[]>(
    () => [
      {
        accessorKey: 'id',
        header: 'ID',
      },
      {
        accessorKey: 'name',
        header: 'Name',
      },
      {
        accessorKey: 'category',
        header: 'Category',
      },
      // ... other columns
    ],
    []
  );

  const table = useMantineReactTable({
    columns,
    data: data ?? [],
    // Optimistic update animation
    mantineTableBodyCellProps: ({ row }) => ({
      style: row.original.id < 0 ? {
        animation: 'shimmer-and-pulse 2s infinite',
        background: `linear-gradient(
          110deg,
          transparent 33%,
          rgba(83, 109, 254, 0.2) 50%,
          transparent 67%
        )`,
        backgroundSize: '200% 100%',
        position: 'relative',
      } : undefined,
    }),
  });

  return <MantineReactTable table={table} />;
};

3. Erstellen des Formulars

Eine Formularkomponente zum Hinzufügen neuer Lebensmittel:

const CreateNewFood = () => {
  const { mutate } = useCreateNewFood();

  const formInputs = [
    { name: 'name', type: 'text' },
    { name: 'category', type: 'text' },
  ];

  const form = useForm<CreateNewFoodType>({
    initialValues: {
      name: '',
      category: '',
      // ... other fields
    },
  });

  return (
    <Box mt="md">
      <form onSubmit={form.onSubmit((data) => mutate(data))}>
        <Flex direction="column" gap="xs">
          {formInputs.map((input) => (
            <TextInput
              key={input.name}
              {...form.getInputProps(input.name)}
              label={input.name}
              tt="uppercase"
              type={input.type}
            />
          ))}
          <Button type="submit" mt="md">
            Create New
          </Button>
        </Flex>
      </form>
    </Box>
  );
};

4. Implementierung optimistischer Updates

Das Herzstück unserer Implementierung – TanStack Query-Mutation mit optimistischen Updates:

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

  return useMutation({
    mutationKey: ['create-new-food'],
    mutationFn: async (data: CreateNewFoodType) => {
      await new Promise(resolve => setTimeout(resolve, 3000)); // Demo delay
      return API.url('/foods').post(data).json<GetAllFoods>();
    },
    onMutate: async (newFood) => {
      // Cancel in-flight queries
      await queryClient.cancelQueries({ queryKey: ['all-foods'] });

      // Snapshot current state
      const previousFoods = queryClient.getQueryData<GetAllFoods[]>(['all-foods']);

      // Create optimistic entry
      const optimisticFood: GetAllFoods = {
        id: -Math.random(),
        ...newFood,
        verified: false,
        createdBy: 0,
        createdAt: new Date().toISOString(),
        updatedAt: new Date().toISOString(),
      };

      // Update cache optimistically
      queryClient.setQueryData(['all-foods'], (old) =>
        old ? [...old, optimisticFood] : [optimisticFood]
      );

      return { previousFoods };
    },
    onError: (err, _, context) => {
      // Rollback on error
      if (context?.previousFoods) {
        queryClient.setQueryData(['all-foods'], context.previousFoods);
      }
    },
    onSettled: () => {
      // Refetch to ensure consistency
      queryClient.invalidateQueries({ queryKey: ['all-foods'] });
    },
  });
};

5. Animationsstile

Die Animation, die unsere optimistischen Updates zum Leben erweckt:

@keyframes shimmer-and-pulse {
  0% {
    background-position: 200% 0;
    transform: scale(1);
    box-shadow: 0 0 0 0 rgba(83, 109, 254, 0.2);
  }
  50% {
    background-position: -200% 0;
    transform: scale(1.02);
    box-shadow: 0 0 0 10px rgba(83, 109, 254, 0);
  }
  100% {
    background-position: 200% 0;
    transform: scale(1);
    box-shadow: 0 0 0 0 rgba(83, 109, 254, 0);
  }
}

Best Practices

  1. Optimistische Updates
    • Aktualisieren Sie die Benutzeroberfläche sofort für eine bessere UX
    • Fehlerfälle mit Rollbacks behandeln
    • Bewahren Sie die Datenkonsistenz durch ordnungsgemäße Invalidierung
  2. Typsicherheit
    • Verwenden Sie TypeScript für eine bessere Wartbarkeit
    • Definieren Sie klare Schnittstellen für Datenstrukturen
    • Nutzen Sie nach Möglichkeit die Typinferenz
  3. Leistung
    • In-Flight-Abfragen während Aktualisierungen abbrechen
    • Verwenden Sie die ordnungsgemäße Abfrageungültigmachung
    • Implementieren Sie eine effiziente Formularstatusverwaltung
  4. Benutzererfahrung
    • Geben Sie umgehend Feedback
    • Ladezustände anzeigen
    • Behandeln Sie Fehler elegant

Zukünftige Verbesserungen

Berücksichtigen Sie diese Verbesserungen für Ihre Implementierung:

  • Funktion zum Rückgängigmachen/Wiederholen
  • Formularvalidierungsregeln
  • Implementierung der Fehlergrenze

Ergebnisse

Building a Data Table with Optimistic Updates

Einmal abgeschlossene Anfrage

Building a Data Table with Optimistic Updates

Abschluss

Diese Implementierung zeigt, wie man mithilfe moderner React-Muster ein robustes Datenverwaltungssystem erstellt. Die Kombination aus TanStack Query, Mantine UI und durchdachten optimistischen Updates sorgt für ein reibungsloses und professionelles Benutzererlebnis.

Denken Sie daran:

  • Halten Sie Ihre Komponenten fokussiert und wartbar
  • Verwaltet alle möglichen Zustände (Laden, Fehler, Erfolg)
  • Verwenden Sie TypeScript für eine bessere Codequalität
  • Berücksichtigen Sie die Benutzererfahrung bei Ihrer Implementierung

Vor welchen Herausforderungen standen Sie bei der Implementierung optimistischer Updates in Ihren React-Anwendungen? Teilen Sie Ihre Erfahrungen in den Kommentaren unten.

Das obige ist der detaillierte Inhalt vonErstellen einer Datentabelle mit optimistischen Aktualisierungen. 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