In diesem Leitfaden behandeln wir Folgendes:
- CRUD-Operationen
- Paginierung
- Redux bleibt bei RTK-Abfrage bestehen
- Verwendung mehrerer Basis-URLs
- Geschützte und öffentliche Routen
- Cache-Verwaltung und Invalidierung
RTK Query ist ein erweitertes Datenabruf- und Caching-Tool, das in Redux Toolkit (RTK) integriert ist. Es optimiert API-Interaktionen durch die Generierung von Redux-Slices und Hooks für häufige Aufgaben wie das Abrufen, Zwischenspeichern und Aktualisieren von Daten. Zu den Hauptmerkmalen gehören:
- Automatisches Caching: RTK Query speichert Daten im Cache und ruft sie automatisch erneut ab, wenn Daten ungültig werden, um sicherzustellen, dass die Benutzeroberfläche immer über die neuesten Daten verfügt.
- Cache-Invalidierung: Mithilfe von Tags können Sie mit RTK Query definieren, wann bestimmte Daten erneut abgerufen werden sollen. Dadurch bleibt Ihr Cache aktuell, ohne dass Daten manuell aktualisiert werden müssen.
- Automatisch generierte Hooks: RTK Query erstellt Hooks für jeden API-Endpunkt, sodass Sie APIs mit einfachen React-Hooks (useGetPostsQuery, useCreatePostMutation usw.) aufrufen können.
- Fehlerbehandlung: Beinhaltet eine benutzerdefinierte Fehlerbehandlung durch Middleware, die das Erkennen und Anzeigen von Fehlern erleichtert.
- Vereinfachte Redux-Integration: RTK Query lässt sich direkt in Redux integrieren, sodass Sie keine zusätzlichen Bibliotheken für die globale Statusverwaltung oder das Caching benötigen.
RTK-Abfrage vs. React-Abfrage
Sowohl React Query als auch RTK Query bieten Lösungen für das Abrufen und Zwischenspeichern von Daten in React-Anwendungen, haben jedoch unterschiedliche Stärken und Anwendungsfälle:
Feature | RTK Query | React Query |
---|---|---|
Purpose | Integrated within Redux for managing server data in Redux state. Best for apps already using Redux or requiring centralized global state. | Dedicated to managing server state with no Redux dependency. Great for apps focused on server state without Redux. |
Caching | Automatic caching with fine-grained cache invalidation through tags. Caches data globally within the Redux store. | Automatic caching with flexible cache control policies. Maintains a separate cache independent of Redux. |
Generated Hooks | Auto-generates hooks for endpoints, allowing mutations and queries using useQuery and useMutation hooks. | Provides hooks (useQuery, useMutation) that work independently from Redux, but require manual configuration of queries and mutations. |
DevTools | Integrated into Redux DevTools, making debugging seamless for Redux users. | Provides its own React Query DevTools, with detailed insight into query states and cache. |
Error Handling | Centralized error handling using Redux middleware. | Error handling within individual queries, with some centralized error-handling options. |
Redux Integration | Built directly into Redux, simplifying usage for Redux-based apps. | Not integrated with Redux by default, although Redux and React Query can be combined if needed. |
Wahl zwischen RTK-Abfrage und Reaktionsabfrage:
-
RTK-Abfrage verwenden wenn:
- Sie verwenden Redux bereits und möchten eine integrierte, optimierte Lösung für den Datenabruf.
- Sie benötigen eine zentralisierte Fehlerbehandlung und Devtools-Integration in Redux.
-
React Query verwenden wenn:
- Sie möchten ein schlankeres Setup ohne Redux-Abhängigkeit.
- Sie bevorzugen eine separate Serverstatusverwaltung und benötigen keinen globalen App-Status.
Im Wesentlichen eignet sich RTK Query hervorragend für Redux-zentrierte Anwendungen, während React Query Flexibilität und Einfachheit für Projekte ohne Redux oder solche mit einem stärker lokalisierten Fokus auf die Serverstatusverwaltung bietet.
1. Speicherkonfiguration und -einrichtung
// src/store/store.js import AsyncStorage from '@react-native-async-storage/async-storage'; import { combineReducers, configureStore, isRejectedWithValue } from '@reduxjs/toolkit'; import { setupListeners } from '@reduxjs/toolkit/query'; import { FLUSH, PAUSE, PERSIST, persistReducer, PURGE, REGISTER, REHYDRATE } from 'redux-persist'; import { authApi } from '../api/authApi'; import { postsApi } from '../api/postsApi'; import { usersApi } from '../api/usersApi'; import authSlice from '../features/auth/authSlice'; const persistConfig = { key: 'root', version: 1, storage: AsyncStorage, blacklist: ['auth', postsApi.middleware, usersApi.middleware, authApi.middleware], // these reduce will not persist data (NOTE: blacklist rtk api slices so that to use tags) // whitelist: ['users'], //these reduce will persist data }; const getEnhancers = (getDefaultEnhancers) => { if (process.env.NODE_ENV === 'development') { const reactotron = require('../reactotronConfig/ReactotronConfig').default; return getDefaultEnhancers().concat(reactotron.createEnhancer()); } return getDefaultEnhancers(); }; /** * On api error this will be called */ export const rtkQueryErrorLogger = (api) => (next) => (action) => { // RTK Query uses `createAsyncThunk` from redux-toolkit under the hood, so we're able to utilize these matchers! if (isRejectedWithValue(action)) { console.log('isRejectedWithValue', action.error, action.payload); alert(JSON.stringify(action)); // This is just an example. You can replace it with your preferred method for displaying notifications. } return next(action); }; const reducer = combineReducers({ auth: authSlice, [postsApi.reducerPath]: postsApi.reducer, [usersApi.reducerPath]: usersApi.reducer, [authApi.reducerPath]: authApi.reducer, }); const persistedReducer = persistReducer(persistConfig, reducer); const store = configureStore({ reducer: persistedReducer, middleware: (getDefaultMiddleware) => getDefaultMiddleware({ serializableCheck: { ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER], }, }).concat(postsApi.middleware, usersApi.middleware, authApi.middleware, rtkQueryErrorLogger), enhancers: getEnhancers, }); setupListeners(store.dispatch); export default store;
Redux Store (src/store/store.js): Der Redux Store ist die Hauptstruktur, die den Status der Anwendung speichert. In Ihrem Setup wird es um redux-persist erweitert, um bestimmte Teile des Redux-Status lokal zu speichern, sodass sie auch beim Neustart der App bestehen bleiben.
-
redux-persist:
- Zweck: Hilft, Teile des Redux-Status über App-Sitzungen hinweg persistent zu halten.
- Konfiguration: Ein persistConfig-Objekt gibt an, dass auth, postsApi und UsersApi nicht beibehalten (auf die schwarze Liste gesetzt) werden sollen, was bedeutet, dass ihre Daten beim Neustart der App zurückgesetzt werden.
- persistReducer kombiniert die Reducer-Konfiguration mit der Persistenzfunktionalität.
Enhancer: Benutzerdefinierte Enhancer werden verwendet, um Reactotron in den Entwicklungsmodus zu integrieren, ein hilfreiches Tool zum Debuggen von Redux-Aktionen, Status und Netzwerkanforderungen. Dies wird nur in der Entwicklung aktiviert und erleichtert das Debuggen, ohne die Produktion zu beeinträchtigen.
-
Middleware:
- RTK-Abfrage-Middlewares (postsApi.middleware, usersApi.middleware, authApi.middleware) fügen Funktionen für die automatische Cache-Verwaltung hinzu und machen den Datenabruf effizient.
- rtkQueryErrorLogger: Eine benutzerdefinierte Middleware protokolliert Fehler, wenn API-Aufrufe fehlschlagen. Es verwendet die isRejectedWithValue-Funktion von RTK Query, um Fehler zu erkennen und zu behandeln, sodass Sie Benutzer auf Probleme aufmerksam machen oder andere Maßnahmen ergreifen können.
setupListeners: Diese Funktion ermöglicht das automatische erneute Abrufen von Daten, wenn bestimmte Ereignisse auftreten, z. B. wenn die App den Fokus wiedererlangt oder aus dem Hintergrund fortfährt, sodass Benutzer ohne manuelle Aktualisierung mit neuen Daten versorgt werden.
2. API-Definitionen mit RTK-Abfrage
RTK Query vereinfacht API-Aufrufe durch automatische Generierung von Redux-Slices, Hooks und Caching. Hier ist eine Aufschlüsselung der von Ihnen definierten APIs:
// src/store/store.js import AsyncStorage from '@react-native-async-storage/async-storage'; import { combineReducers, configureStore, isRejectedWithValue } from '@reduxjs/toolkit'; import { setupListeners } from '@reduxjs/toolkit/query'; import { FLUSH, PAUSE, PERSIST, persistReducer, PURGE, REGISTER, REHYDRATE } from 'redux-persist'; import { authApi } from '../api/authApi'; import { postsApi } from '../api/postsApi'; import { usersApi } from '../api/usersApi'; import authSlice from '../features/auth/authSlice'; const persistConfig = { key: 'root', version: 1, storage: AsyncStorage, blacklist: ['auth', postsApi.middleware, usersApi.middleware, authApi.middleware], // these reduce will not persist data (NOTE: blacklist rtk api slices so that to use tags) // whitelist: ['users'], //these reduce will persist data }; const getEnhancers = (getDefaultEnhancers) => { if (process.env.NODE_ENV === 'development') { const reactotron = require('../reactotronConfig/ReactotronConfig').default; return getDefaultEnhancers().concat(reactotron.createEnhancer()); } return getDefaultEnhancers(); }; /** * On api error this will be called */ export const rtkQueryErrorLogger = (api) => (next) => (action) => { // RTK Query uses `createAsyncThunk` from redux-toolkit under the hood, so we're able to utilize these matchers! if (isRejectedWithValue(action)) { console.log('isRejectedWithValue', action.error, action.payload); alert(JSON.stringify(action)); // This is just an example. You can replace it with your preferred method for displaying notifications. } return next(action); }; const reducer = combineReducers({ auth: authSlice, [postsApi.reducerPath]: postsApi.reducer, [usersApi.reducerPath]: usersApi.reducer, [authApi.reducerPath]: authApi.reducer, }); const persistedReducer = persistReducer(persistConfig, reducer); const store = configureStore({ reducer: persistedReducer, middleware: (getDefaultMiddleware) => getDefaultMiddleware({ serializableCheck: { ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER], }, }).concat(postsApi.middleware, usersApi.middleware, authApi.middleware, rtkQueryErrorLogger), enhancers: getEnhancers, }); setupListeners(store.dispatch); export default store;
-
authApi (src/api/authApi.js):
- Definiert eine Anmeldemutation, die Benutzeranmeldeinformationen (z. B. Benutzername, Passwort) zur Authentifizierung an den Server sendet.
- onQueryStarted: Sobald die Anmeldung erfolgreich ist, wird das zurückgegebene Token mithilfe der setToken-Aktion in Redux gespeichert. Dies ermöglicht sichere, authentifizierte Anfragen an andere Endpunkte.
// src/api/authApi.js import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; import { setToken } from '../features/auth/authSlice'; export const authApi = createApi({ reducerPath: 'authApi', baseQuery: fetchBaseQuery({ baseUrl: 'https://dummyjson.com/auth/', }), endpoints: (builder) => ({ login: builder.mutation({ query: (credentials) => ({ url: 'login', method: 'POST', body: credentials, }), async onQueryStarted(arg, { dispatch, queryFulfilled }) { try { const { data } = await queryFulfilled; dispatch(setToken(data.accessToken)); // Store the token in Redux } catch (error) { console.error('Login error:', error); } }, }), }), }); export const { useLoginMutation } = authApi;
-
postsApi (src/api/postsApi.js):
-
CRUD-Operationen: Die Posts-API enthält mehrere Endpunkte für die Interaktion mit Posts (Abrufen, Erstellen, Aktualisieren, Löschen).
- getPosts: Ruft paginierte Beiträge ab, d. h. es ruft Daten in kleineren Blöcken (Seiten) ab und verbessert so die Leistung und Ladezeiten.
- createPost, updatePost und deletePost: Jeder von ihnen führt eine andere Aktion aus (einen Beitrag erstellen, aktualisieren oder löschen).
- Tags für das Caching: Jeder Endpunkt verwendet Tags (z. B. { Typ: 'Beiträge', ID }), um die Cache-Invalidierung und -Aktualisierung automatisch zu verwalten. Wenn Sie beispielsweise einen Beitrag erstellen oder löschen, wird der Cache ungültig und getPosts wird aufgefordert, neue Daten ohne manuelles Eingreifen abzurufen.
-
CRUD-Operationen: Die Posts-API enthält mehrere Endpunkte für die Interaktion mit Posts (Abrufen, Erstellen, Aktualisieren, Löschen).
// src/store/store.js import AsyncStorage from '@react-native-async-storage/async-storage'; import { combineReducers, configureStore, isRejectedWithValue } from '@reduxjs/toolkit'; import { setupListeners } from '@reduxjs/toolkit/query'; import { FLUSH, PAUSE, PERSIST, persistReducer, PURGE, REGISTER, REHYDRATE } from 'redux-persist'; import { authApi } from '../api/authApi'; import { postsApi } from '../api/postsApi'; import { usersApi } from '../api/usersApi'; import authSlice from '../features/auth/authSlice'; const persistConfig = { key: 'root', version: 1, storage: AsyncStorage, blacklist: ['auth', postsApi.middleware, usersApi.middleware, authApi.middleware], // these reduce will not persist data (NOTE: blacklist rtk api slices so that to use tags) // whitelist: ['users'], //these reduce will persist data }; const getEnhancers = (getDefaultEnhancers) => { if (process.env.NODE_ENV === 'development') { const reactotron = require('../reactotronConfig/ReactotronConfig').default; return getDefaultEnhancers().concat(reactotron.createEnhancer()); } return getDefaultEnhancers(); }; /** * On api error this will be called */ export const rtkQueryErrorLogger = (api) => (next) => (action) => { // RTK Query uses `createAsyncThunk` from redux-toolkit under the hood, so we're able to utilize these matchers! if (isRejectedWithValue(action)) { console.log('isRejectedWithValue', action.error, action.payload); alert(JSON.stringify(action)); // This is just an example. You can replace it with your preferred method for displaying notifications. } return next(action); }; const reducer = combineReducers({ auth: authSlice, [postsApi.reducerPath]: postsApi.reducer, [usersApi.reducerPath]: usersApi.reducer, [authApi.reducerPath]: authApi.reducer, }); const persistedReducer = persistReducer(persistConfig, reducer); const store = configureStore({ reducer: persistedReducer, middleware: (getDefaultMiddleware) => getDefaultMiddleware({ serializableCheck: { ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER], }, }).concat(postsApi.middleware, usersApi.middleware, authApi.middleware, rtkQueryErrorLogger), enhancers: getEnhancers, }); setupListeners(store.dispatch); export default store;
-
usersApi (src/api/usersApi.js):
- Diese API ruft das Profil des authentifizierten Benutzers ab und richtet Autorisierungsheader basierend auf dem Token von Redux ein.
- Header: PrepareHeaders hängt das Token dynamisch an jede Anfrage an, sofern verfügbar, und ermöglicht so sichere und autorisierte API-Anfragen.
3. Auth-Slice (src/features/auth/authSlice.js)
// src/api/authApi.js import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; import { setToken } from '../features/auth/authSlice'; export const authApi = createApi({ reducerPath: 'authApi', baseQuery: fetchBaseQuery({ baseUrl: 'https://dummyjson.com/auth/', }), endpoints: (builder) => ({ login: builder.mutation({ query: (credentials) => ({ url: 'login', method: 'POST', body: credentials, }), async onQueryStarted(arg, { dispatch, queryFulfilled }) { try { const { data } = await queryFulfilled; dispatch(setToken(data.accessToken)); // Store the token in Redux } catch (error) { console.error('Login error:', error); } }, }), }), }); export const { useLoginMutation } = authApi;
- authSlice: Ein Redux-Slice verwaltet einen bestimmten Zustand, in diesem Fall die Benutzerauthentifizierung.
- Statusverwaltung: Der authSlice behält das Token des Benutzers, das für den Zugriff auf geschützte API-Endpunkte verwendet wird.
-
Aktionen:
- setToken: Speichert das Authentifizierungstoken im Redux-Status.
- Abmelden: Löscht das Token von Redux und meldet den Benutzer effektiv ab.
4. Reactotron zum Debuggen (src/reactotronConfig/ReactotronConfig.js)
// src/api/postsApi.js import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; // Define the postsApi slice with RTK Query export const postsApi = createApi({ // Unique key for the API slice in Redux state reducerPath: 'postsApi', // Configure base query settings, including the base URL for all requests baseQuery: fetchBaseQuery({ baseUrl: 'https://jsonplaceholder.typicode.com', }), // Define cache tag types for automatic cache invalidation tagTypes: ['Posts'], // Define API endpoints (queries and mutations) endpoints: (builder) => ({ // Query to fetch a paginated list of posts getPosts: builder.query({ // URL and parameters for paginated posts query: ({ page = 1, limit = 10 }) => `/posts?_page=${page}&_limit=${limit}`, // Tagging posts to automatically refresh this cache when needed providesTags: (result) => result ? [...result.map(({ id }) => ({ type: 'Posts', id })), { type: 'Posts', id: 'LIST' }] : [{ type: 'Posts', id: 'LIST' }], }), // Query to fetch a single post by its ID getPostById: builder.query({ // Define query with post ID in the URL path query: (id) => `/posts/${id}`, // Tag individual post by ID for selective cache invalidation providesTags: (result, error, id) => [{ type: 'Posts', id }], }), // Mutation to create a new post createPost: builder.mutation({ // Configure the POST request details and payload query: (newPost) => ({ url: '/posts', method: 'POST', body: newPost, }), // Invalidate all posts (paginated list) to refresh after creating a post invalidatesTags: [{ type: 'Posts', id: 'LIST' }], }), // Mutation to update an existing post by its ID updatePost: builder.mutation({ // Define the PUT request with post ID and updated data in the payload query: ({ id, ...updatedData }) => ({ url: `/posts/${id}`, method: 'PUT', body: updatedData, }), // Invalidate cache for both the updated post and the paginated list invalidatesTags: (result, error, { id }) => [ { type: 'Posts', id }, { type: 'Posts', id: 'LIST' }, ], }), // Mutation to delete a post by its ID deletePost: builder.mutation({ // Define the DELETE request with post ID in the URL path query: (id) => ({ url: `/posts/${id}`, method: 'DELETE', }), // Invalidate cache for the deleted post and the paginated list invalidatesTags: (result, error, id) => [ { type: 'Posts', id }, { type: 'Posts', id: 'LIST' }, ], }), }), }); // Export generated hooks for each endpoint to use them in components export const { useGetPostsQuery, // Use this when you want data to be fetched automatically as the component mounts or when the query parameters change. useLazyGetPostsQuery, // Use this when you need more control over when the query runs, such as in response to a user action (e.g., clicking a button), conditional fetching, or specific events. useGetPostByIdQuery, useCreatePostMutation, useUpdatePostMutation, useDeletePostMutation, } = postsApi;
- Reactotron: Reactotron ist ein Debugging-Tool, das dabei hilft, Redux-Statusänderungen zu verfolgen, API-Anfragen zu überwachen und Protokolle zu überprüfen.
- Setup: Konfiguriert, um console.log-Ausgaben und Redux-Aktionen zu erfassen. Im Entwicklungsmodus bietet dieses Setup eine leistungsstarke Möglichkeit zum Debuggen, ohne zusätzlichen Code hinzuzufügen oder die Produktionsleistung zu verändern.
5. Hauptanwendungskomponenten
// src/api/usersApi.js import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; export const usersApi = createApi({ reducerPath: 'usersApi', baseQuery: fetchBaseQuery({ baseUrl: 'https://dummyjson.com', prepareHeaders: (headers, { getState }) => { // Get the token from the Redux auth state const { token } = getState().auth; // If the token exists, set it in the Authorization header if (token) { headers.set('Authorization', `Bearer ${token}`); } // Optional: include credentials if needed by the API headers.set('credentials', 'include'); return headers; }, }), endpoints: (builder) => ({ // Fetch user profile with token in Authorization header getUserProfile: builder.query({ query: () => '/auth/me', }), }), }); export const { useGetUserProfileQuery } = usersApi;
-
App-Komponente (src/App.js):
- Die App-Komponente umschließt die gesamte Anwendung in Provider (um Redux verfügbar zu machen) und PersistGate (um das Rendern zu verzögern, bis der persistente Zustand abgerufen wurde).
- PersistGate sorgt dafür, dass Daten dauerhaft geladen werden, bevor die App angezeigt wird, und reduziert so Inkonsistenzen bei der Ladezeit.
// src/MainApp.js import React, { useEffect, useState } from 'react'; importieren { Aktivitätsindikator, Taste, FlatList, Modal, RefreshControl, StyleSheet, Text, Texteingabe, Sicht, } von 'react-native'; import { SafeAreaView } aus 'react-native-safe-area-context'; import { useDispatch, useSelector } from 'react-redux'; import { useLoginMutation } from './api/authApi'; importieren { useCreatePostMutation, useDeletePostMutation, useGetPostsQuery, useLazyGetPostsQuery, useUpdatePostMutation, } from './api/postsApi'; import { useGetUserProfileQuery } from './api/usersApi'; importieren {abmelden}von './features/auth/authSlice'; const MainApp = () => { const [newPostTitle, setNewPostTitle] = useState(''); const [page, setPage] = useState(1); const [postsData, setPostsData] = useState([]); const [refreshing, setRefreshing] = useState(false); const [isModalVisible, setModalVisible] = useState(false); const distribution = useDispatch(); const token = useSelector((state) => state.auth.token); // Login-Mutation const [login, { isLoading: isLoggingIn }] = useLoginMutation(); // Benutzerprofil abrufen, wenn Token verfügbar ist const { data: userProfile, refetch: refetchUserProfile } = useGetUserProfileQuery(undefiniert, { überspringen: !token, }); // Paginierte Beiträge abrufen const { Daten: Beiträge, wird geladen, isFetching, isError, erneut abrufen, } = useGetPostsQuery({ page, limit: 10 }); // Der useQuery-Hook wird verwendet, wenn Sie Daten beim Laden des Bildschirms abrufen möchten. Rufen Sie beispielsweise das Benutzerprofil auf dem Profilbildschirm ab. // Verwenden Sie die Lazy-Abfrage für die Aktualisierung, um Seite 1 direkt abzurufen const [triggerFetchFirstPage, { data: lazyData }] = useLazyGetPostsQuery(); // useLazyquery wird verwendet, wenn Sie den API-Aufruf steuern möchten, z. B. beim Klicken auf eine Schaltfläche. const [createPost] = useCreatePostMutation(); const [updatePost] = useUpdatePostMutation(); const [deletePost] = useDeletePostMutation(); useEffect(() => { if (Beiträge) { setPostsData((prevData) => (page === 1 ? posts : [...prevData, ...posts])); } }, [Beiträge, Seite]); // Login-Handler const handleLogin = async () => { versuchen { const credentials = { Benutzername: 'emilys', Passwort: 'emilyspass' }; Warten Sie auf die Anmeldung (Anmeldeinformationen); console.log('userProfile', userProfile); refetchUserProfile(); } Catch (Fehler) { console.error('Anmeldung fehlgeschlagen:', Fehler); } }; const handleRefresh = async () => { setRefreshing(true); setPage(1); // Setze die Seite für die nächsten Scrolls auf 1 zurück setPostsData([]); // Löschen Sie die Daten, um Duplikate zu vermeiden // Den ersten Seitenabruf explizit auslösen const { data } = waiting triggerFetchFirstPage({ page: 1, limit: 10 }); if (Daten) { setPostsData(data); // Setze die Beitragsdaten auf die Ergebnisse der ersten Seite } setRefreshing(false); }; // Einen neuen Beitrag erstellen, ihn oben hinzufügen und die Liste erneut abrufen const handleCreatePost = async () => { if (newPostTitle) { const { data: newPost } = waiting createPost({ title: newPostTitle, body: 'New post content' }); setNewPostTitle(''); setPostsData((prevData) => [newPost, ...prevData]); refetch(); } }; // Einen vorhandenen Beitrag aktualisieren und „HASAN“ zum Titel hinzufügen const handleUpdatePost = async (post) => { const { data: updatePost } = waiting updatePost({ ID: post.id, Titel: `${post.title} HASAN`, }); setPostsData((prevData) => prevData.map((item) => (item?.id === aktualisierterBeitrag?.id ? aktualisierterBeitrag: Artikel)) ); }; // Einen Beitrag löschen und ihn sofort aus der Benutzeroberfläche entfernen const handleDeletePost = async (id) => { Warten auf deletePost(id); setPostsData((prevData) => prevData.filter((post) => post.id !== id)); }; // Laden Sie mehr Beiträge für endloses Scrollen const loadMorePosts = () => { if (!isFetching) { setPage((prevPage) => prevPage 1); } }; // Modale Sichtbarkeit umschalten const toggleModal = () => { setModalVisible(!isModalVisible); }; if (isLoading && page === 1) return <text>Loading...</text>; if (isError) return <text>Fehler beim Abrufen von Beiträgen.</text>; zurückkehren ( <safeareaview> <ul> <li> <strong>MainApp-Komponente (src/MainApp.js)</strong>: <ul> <li> <strong>Status und Hooks</strong>: Verwaltet lokale Status (z. B. für die Paginierung von Beiträgen) und Hooks wie useLoginMutation, um Aktionen bei bestimmten Ereignissen auszulösen.</li> <li> <strong>Anmelden</strong>: <ul> <li>Verwendet useLoginMutation, um den Benutzer anzumelden, und löst dann refetchUserProfile aus, um die Benutzerprofildaten zu laden.</li> <li> <em>Bedingte Abfrage</em>: Ruft das Benutzerprofil nur ab, wenn ein gültiges Token vorhanden ist (überspringen: !token), wodurch unnötige API-Aufrufe reduziert werden.</li> </ul> </li> <li> <strong>Beiträge abrufen</strong>: <ul> <li>Verwendet useGetPostsQuery zum Abrufen paginierter Beiträge und unterstützt das unendliche Scrollen, indem mehr Daten abgerufen werden, während der Benutzer scrollt.</li> <li> <em>Aktualisierungssteuerung</em>: Ermöglicht Benutzern das Aktualisieren der Beitragsliste, nützlich für die Pull-to-Refresh-Funktion auf Mobilgeräten.</li> </ul> </li> <li> <strong>Beiträge erstellen, aktualisieren, löschen</strong>: <ul> <li> <em>Erstellen</em>: Ruft createPost auf und aktualisiert sofort die Beitragsliste mit dem neuen Beitrag ganz oben.</li> <li> <em>Aktualisieren</em>: Hängt beim Aktualisieren „HASAN“ an den Titel eines Beitrags an.</li> <li> <em>Löschen</em>: Entfernt einen Beitrag und aktualisiert die Benutzeroberfläche, ohne dass die Seite neu geladen werden muss, dank der Cache-Ungültigmachung von deletePost.</li> </ul> </li> <li> <strong>UI-Elemente</strong>: <ul> <li>Ein Modal zeigt das Benutzerprofil an. Die Profilschaltfläche wird nur angezeigt, wenn Benutzerprofildaten geladen sind, was das Benutzererlebnis verbessert.</li> </ul> </li> <li> <strong>FlatList</strong>: Zeigt Beiträge in einem scrollbaren, paginierten Format an und verbessert so die Benutzerfreundlichkeit.</li> </ul> </li> </ul> <hr> <h2> Zusammenfassung: </h2> <p>Ihre React Native-App verwendet <strong>Redux Toolkit (RTK) Query</strong> für effiziente Datenverwaltung und API-Interaktionen. Das Setup umfasst:</p> <ol> <li><p><strong>Store-Konfiguration</strong>: Redux-Store mit Redux-Persist zum Speichern spezifischer Daten über App-Sitzungen hinweg, eine benutzerdefinierte Middleware für die Fehlerprotokollierung und Reactotron für das Debuggen im Entwicklungsmodus.</p></li> <li> <p><strong>APIs mit RTK-Abfrage</strong>:</p> <ul> <li> <strong>authApi</strong> übernimmt die Authentifizierung mit einer Login-Mutation und speichert das Token in Redux.</li> <li> <strong>postsApi</strong> stellt CRUD-Operationen für Beiträge bereit und verwendet Cache-Tags, um Daten automatisch zu aktualisieren, wenn Beiträge hinzugefügt, aktualisiert oder gelöscht werden.</li> <li> <strong>usersApi</strong> ruft das Benutzerprofil mit dynamischen tokenbasierten Autorisierungsheadern ab.</li> </ul> </li> <li><p><strong>Auth Slice</strong>: Verwaltet das Authentifizierungstoken und stellt Aktionen zum Festlegen oder Löschen des Tokens beim Anmelden/Abmelden bereit.</p></li> <li> <p><strong>App- und MainApp-Komponenten</strong>:</p> <ul> <li>Die Haupt-App verpackt Komponenten in Provider und PersistGate und stellt so sicher, dass der Status vor dem Rendern geladen wird.</li> <li> MainApp verwaltet das Abrufen, Erstellen, Aktualisieren und Löschen von Beiträgen. Es lädt Daten bedingt (z. B. ruft das Benutzerprofil nur ab, wenn ein Token vorhanden ist), unterstützt Paginierung und unendliches Scrollen </li> <li>Verwendet FlatList für eine paginierte Beitragsliste, Modalitäten für das Profil und grundlegende Stile für ein sauberes, organisiertes Layout.</li> </ul> </li> </ol> <blockquote> <p>VOLLSTÄNDIGER CODE-></p> </blockquote> </safeareaview>
Das obige ist der detaillierte Inhalt vonEffiziente Datenverarbeitung in React Native mit RTK-Abfrage. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Ich habe eine funktionale SaaS-Anwendung mit mehreren Mandanten (eine EdTech-App) mit Ihrem täglichen Tech-Tool erstellt und Sie können dasselbe tun. Was ist eine SaaS-Anwendung mit mehreren Mietern? Mit Multi-Tenant-SaaS-Anwendungen können Sie mehrere Kunden aus einem Sing bedienen

Dieser Artikel zeigt die Frontend -Integration mit einem Backend, das durch die Genehmigung gesichert ist und eine funktionale edtech SaaS -Anwendung unter Verwendung von Next.js. erstellt. Die Frontend erfasst Benutzerberechtigungen zur Steuerung der UI-Sichtbarkeit und stellt sicher, dass API-Anfragen die Rollenbasis einhalten

JavaScript ist die Kernsprache der modernen Webentwicklung und wird für seine Vielfalt und Flexibilität häufig verwendet. 1) Front-End-Entwicklung: Erstellen Sie dynamische Webseiten und einseitige Anwendungen durch DOM-Operationen und moderne Rahmenbedingungen (wie React, Vue.js, Angular). 2) Serverseitige Entwicklung: Node.js verwendet ein nicht blockierendes E/A-Modell, um hohe Parallelitäts- und Echtzeitanwendungen zu verarbeiten. 3) Entwicklung von Mobil- und Desktop-Anwendungen: Die plattformübergreifende Entwicklung wird durch reaktnative und elektronen zur Verbesserung der Entwicklungseffizienz realisiert.

Zu den neuesten Trends im JavaScript gehören der Aufstieg von Typenkripten, die Popularität moderner Frameworks und Bibliotheken und die Anwendung der WebAssembly. Zukunftsaussichten umfassen leistungsfähigere Typsysteme, die Entwicklung des serverseitigen JavaScript, die Erweiterung der künstlichen Intelligenz und des maschinellen Lernens sowie das Potenzial von IoT und Edge Computing.

JavaScript ist der Eckpfeiler der modernen Webentwicklung. Zu den Hauptfunktionen gehören eine ereignisorientierte Programmierung, die Erzeugung der dynamischen Inhalte und die asynchrone Programmierung. 1) Ereignisgesteuerte Programmierung ermöglicht es Webseiten, sich dynamisch entsprechend den Benutzeroperationen zu ändern. 2) Die dynamische Inhaltsgenerierung ermöglicht die Anpassung der Seiteninhalte gemäß den Bedingungen. 3) Asynchrone Programmierung stellt sicher, dass die Benutzeroberfläche nicht blockiert ist. JavaScript wird häufig in der Webinteraktion, der einseitigen Anwendung und der serverseitigen Entwicklung verwendet, wodurch die Flexibilität der Benutzererfahrung und die plattformübergreifende Entwicklung erheblich verbessert wird.

Python eignet sich besser für Datenwissenschaft und maschinelles Lernen, während JavaScript besser für die Entwicklung von Front-End- und Vollstapel geeignet ist. 1. Python ist bekannt für seine prägnante Syntax- und Rich -Bibliotheks -Ökosystems und ist für die Datenanalyse und die Webentwicklung geeignet. 2. JavaScript ist der Kern der Front-End-Entwicklung. Node.js unterstützt die serverseitige Programmierung und eignet sich für die Entwicklung der Vollstapel.

JavaScript erfordert keine Installation, da es bereits in moderne Browser integriert ist. Sie benötigen nur einen Texteditor und einen Browser, um loszulegen. 1) Führen Sie sie in der Browser -Umgebung durch, indem Sie die HTML -Datei durch Tags einbetten. 2) Führen Sie die JavaScript -Datei nach dem Herunterladen und Installieren von node.js nach dem Herunterladen und Installieren der Befehlszeile aus.

So senden Sie im Voraus Aufgabenbenachrichtigungen in Quartz Wenn der Quartz -Timer eine Aufgabe plant, wird die Ausführungszeit der Aufgabe durch den Cron -Ausdruck festgelegt. Jetzt...


Heiße KI -Werkzeuge

Undresser.AI Undress
KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover
Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool
Ausziehbilder kostenlos

Clothoff.io
KI-Kleiderentferner

AI Hentai Generator
Erstellen Sie kostenlos Ai Hentai.

Heißer Artikel

Heiße Werkzeuge

MinGW – Minimalistisches GNU für Windows
Dieses Projekt wird derzeit auf osdn.net/projects/mingw migriert. Sie können uns dort weiterhin folgen. MinGW: Eine native Windows-Portierung der GNU Compiler Collection (GCC), frei verteilbare Importbibliotheken und Header-Dateien zum Erstellen nativer Windows-Anwendungen, einschließlich Erweiterungen der MSVC-Laufzeit zur Unterstützung der C99-Funktionalität. Die gesamte MinGW-Software kann auf 64-Bit-Windows-Plattformen ausgeführt werden.

PHPStorm Mac-Version
Das neueste (2018.2.1) professionelle, integrierte PHP-Entwicklungstool

SublimeText3 chinesische Version
Chinesische Version, sehr einfach zu bedienen

SublimeText3 Englische Version
Empfohlen: Win-Version, unterstützt Code-Eingabeaufforderungen!

Senden Sie Studio 13.0.1
Leistungsstarke integrierte PHP-Entwicklungsumgebung