Maison >interface Web >js tutoriel >Gestion efficace des données dans React Native avec requête RTK

Gestion efficace des données dans React Native avec requête RTK

Mary-Kate Olsen
Mary-Kate Olsenoriginal
2024-11-30 10:01:14940parcourir

Dans ce guide, nous aborderons :

  • Opérations CRUD
  • Pagination
  • Redux persiste avec la requête RTK
  • Utilisation de plusieurs URL de base
  • Voies protégées et publiques
  • Gestion et invalidation du cache

Efficient Data Handling in React Native with RTK Query

RTK Query est un outil avancé de récupération de données et de mise en cache intégré à Redux Toolkit (RTK). Il rationalise les interactions API en générant des tranches et des hooks Redux pour les tâches courantes telles que la récupération, la mise en cache et la mise à jour des données. Les principales fonctionnalités incluent :

  1. Mise en cache automatique : la requête RTK met en cache les données et les récupère automatiquement lorsque les données sont invalidées, garantissant ainsi que l'interface utilisateur dispose toujours des données les plus récentes.
  2. Invalidation du cache : à l'aide de balises, RTK Query vous permet de définir quand certaines données doivent être récupérées. Cela permet de garder votre cache à jour sans mettre à jour manuellement les données.
  3. Hooks générés automatiquement : RTK Query crée des hooks pour chaque point de terminaison d'API, vous permettant d'appeler des API à l'aide de hooks React simples (useGetPostsQuery, useCreatePostMutation, etc.).
  4. Gestion des erreurs : inclut une gestion personnalisée des erreurs via un middleware, ce qui facilite la détection et l'affichage des erreurs.
  5. Intégration Redux simplifiée : RTK Query s'intègre directement à Redux, vous n'avez donc pas besoin de bibliothèques supplémentaires pour la gestion globale de l'état ou la mise en cache.

Requête RTK et requête React

React Query et RTK Query fournissent tous deux des solutions pour la récupération et la mise en cache des données dans les applications React, mais ils ont des atouts et des cas d'utilisation différents :

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.

Choisir entre la requête RTK et la requête React :

  • Utiliser la requête RTK si :

    • Vous utilisez déjà Redux et souhaitez une solution intégrée et rationalisée pour la récupération de données.
    • Vous avez besoin d'une gestion centralisée des erreurs et de l'intégration des outils de développement dans Redux.
  • Utilisez React Query si :

    • Vous souhaitez une configuration plus légère sans dépendance Redux.
    • Vous préférez une gestion séparée de l'état du serveur et n'avez pas besoin de l'état global de l'application.

Essentiellement, RTK Query excelle pour les applications centrées sur Redux, tandis que React Query offre flexibilité et simplicité pour les projets sans Redux ou ceux avec une gestion plus localisée de l'état du serveur.


Efficient Data Handling in React Native with RTK Query



1. Configuration et configuration du magasin

// 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) : Le magasin Redux est la structure principale détenant l'état de l'application. Dans votre configuration, il est amélioré avec redux-persist pour enregistrer localement certaines parties de l'état Redux, afin qu'elles persistent même lorsque l'application redémarre.

  • redux-persist :

    • Objectif : Aide à maintenir certaines parties de l'état Redux persistantes au fil des sessions d'application.
    • Configuration : un objet persistConfig spécifie qu'auth, postsApi et usersApi ne doivent pas être persistants (liste noire), ce qui signifie que leurs données sont réinitialisées au redémarrage de l'application.
    • persistReducer combine la configuration du réducteur avec la fonctionnalité de persistance.
  • Enhancers : des Enhancers personnalisés sont utilisés pour intégrer Reactotron en mode développement, un outil utile pour déboguer les actions Redux, l'état et les requêtes réseau. Cela ne s'active qu'en développement, ce qui facilite le débogage sans affecter la production.

  • Middleware :

    • Les middlewares RTK Query (postsApi.middleware, usersApi.middleware, authApi.middleware) ajoutent des fonctionnalités pour la gestion automatique du cache, rendant la récupération de données efficace.
    • rtkQueryErrorLogger : un middleware personnalisé enregistre les erreurs lorsque les appels d'API échouent. Il utilise la fonction isRejectedWithValue de RTK Query pour détecter et gérer les erreurs, vous permettant ainsi d'alerter les utilisateurs des problèmes ou de prendre d'autres actions.
  • setupListeners : Cette fonction permet la récupération automatique des données lorsque certains événements se produisent, comme lorsque l'application retrouve le focus ou reprend en arrière-plan, fournissant aux utilisateurs de nouvelles données sans actualisation manuelle.



2. Définitions API avec requête RTK

RTK Query simplifie les appels d'API en générant automatiquement des tranches Redux, des hooks et une mise en cache. Voici une répartition des API que vous avez définies :

// 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) :
    • Définit une mutation de connexion qui envoie les informations d'identification de l'utilisateur (par exemple, nom d'utilisateur, mot de passe) au serveur pour s'authentifier.
    • onQueryStarted : une fois la connexion réussie, il stocke le jeton renvoyé dans Redux à l'aide de l'action setToken. Cela permet des requêtes sécurisées et authentifiées vers d'autres points de terminaison.

// 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) :
    • Opérations CRUD : l'API des publications contient plusieurs points de terminaison pour interagir avec les publications (récupérer, créer, mettre à jour, supprimer).
      • getPosts : récupère les publications paginées, ce qui signifie qu'il récupère les données en morceaux plus petits (pages), améliorant ainsi les performances et les temps de chargement.
      • createPost, updatePost et deletePost : chacun d'entre eux effectue une action différente (créer, mettre à jour ou supprimer une publication).
    • Balises pour la mise en cache : chaque point de terminaison utilise des balises (par exemple, { type : 'Posts', id }) pour gérer automatiquement l'invalidation et le rafraîchissement du cache. Par exemple, la création ou la suppression d'une publication invalide le cache, invitant getPosts à récupérer de nouvelles données sans intervention manuelle.

// 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) :
    • Cette API récupère le profil de l'utilisateur authentifié, en configurant les en-têtes d'autorisation basés sur le jeton de Redux.
    • En-têtes : PrepareHeaders attache dynamiquement le jeton à chaque demande s'il est disponible, permettant des requêtes API sécurisées et autorisées.


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 : Une tranche Redux gère un élément d'état spécifique, dans ce cas, l'authentification de l'utilisateur.
  • Gestion de l'état : authSlice conserve le jeton de l'utilisateur, qui est utilisé pour accéder aux points de terminaison de l'API protégés.
  • Actions :
    • setToken : stocke le jeton d'authentification dans l'état Redux.
    • déconnexion : efface le jeton de Redux, déconnectant ainsi l'utilisateur.


4. Reactotron pour le débogage (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 est un outil de débogage qui permet de suivre les changements d'état de Redux, de surveiller les demandes d'API et d'inspecter les journaux.
  • Configuration : configuré pour capturer les sorties console.log et les actions Redux. En mode développement, cette configuration fournit un moyen puissant de déboguer sans ajouter de code supplémentaire ni altérer les performances de production.


5. Principaux composants de l'application

// 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;
  • Composant d'application (src/App.js) :
    • Le composant App enveloppe l'intégralité de l'application dans Provider (pour rendre Redux disponible) et PersistGate (pour retarder le rendu jusqu'à ce que l'état persistant ait été récupéré).
    • PersistGate garantit le chargement des données persistantes avant l'affichage de l'application, réduisant ainsi les incohérences du temps de chargement.

// src/MainApp.js
importer React, { useEffect, useState } depuis 'react' ;
importer {
  Indicateur d'activité,
  Bouton,
  Liste plate,
  Modal,
  ActualiserContrôle,
  Feuille de style,
  Texte,
  Entrée de texte,
  Voir,
} de « réagir-natif » ;
importer { SafeAreaView } depuis 'react-native-safe-area-context' ;
importer { useDispatch, useSelector } depuis 'react-redux' ;
importer { useLoginMutation } depuis './api/authApi' ;
importer {
  utilisezCreatePostMutation,
  useDeletePostMutation,
  utilisezGetPostsQuery,
  utilisezLazyGetPostsQuery,
  useUpdatePostMutation,
} depuis './api/postsApi';
importer { useGetUserProfileQuery } depuis './api/usersApi' ;
importer { déconnexion }de './features/auth/authSlice';

const MainApp = () => {
  const [newPostTitle, setNewPostTitle] = useState('');
  const [page, setPage] = useState(1);
  const [postsData, setPostsData] = useState([]);
  const [rafraîchissant, setRefreshing] = useState(false);
  const [isModalVisible, setModalVisible] = useState(false);

  const dispatch = useDispatch();
  const token = useSelector((state) => state.auth.token);

  // Mutation de connexion
  const [login, { isLoading : isLoggingIn }] = useLoginMutation();

  // Récupère le profil utilisateur lorsque le jeton est disponible
  const { données : userProfile, refetch : refetchUserProfile } = useGetUserProfileQuery (non défini, {
    sauter : !jeton,
  });

  // Récupère les messages paginés
  const {
    données : postes,
    est en cours de chargement,
    estRécupération,
    estErreur,
    récupérer,
  } = useGetPostsQuery({ page, limite : 10 }); // Le hook useQuery est utilisé lorsque vous souhaitez récupérer des données lors du chargement de l'écran. Par exemple, récupérez le profil utilisateur sur l'écran de profil.
  // Utilisez la requête paresseuse pour actualiser pour récupérer directement la page 1
  const [triggerFetchFirstPage, { data: lazyData }] = useLazyGetPostsQuery(); // useLazyquery est utilisé lorsque vous souhaitez contrôler l'appel de l'API, comme lors d'un clic sur un bouton.

  const [createPost] = useCreatePostMutation();
  const [updatePost] = useUpdatePostMutation();
  const [deletePost] = useDeletePostMutation();

  useEffect(() => {
    si (messages) {
      setPostsData((prevData) => (page === 1 ? posts : [...prevData, ...posts]));
    }
  }, [messages, page]);

  // Gestionnaire de connexion
  const handleLogin = async () => {
    essayer {
      const identifiants = { nom d'utilisateur : 'emilys', mot de passe : 'emilyspass' } ;
      attendre la connexion (informations d'identification) ;
      console.log('userProfile', userProfile);
      refetchUserProfile();
    } attraper (erreur) {
      console.error('Échec de la connexion :', erreur);
    }
  } ;

  const handleRefresh = async () => {
    setRefreshing(true);
    setPage(1); // Remet la page à 1 pour les prochains scrolls
    setPostsData([]); // Efface les données pour éviter les duplications

    // Déclenche explicitement la récupération de la première page
    const { data } = wait triggerFetchFirstPage({ page : 1, limite : 10 });

    si (données) {
      setPostsData(données); // Définit les données des publications sur les résultats de la première page
    }

    setRefreshing(faux);
  } ;

  // Crée un nouveau message, l'ajoute en haut et récupère la liste
  const handleCreatePost = async () => {
    si (nouveau titre de poste) {
      const { data : newPost } = wait createPost ({ title : newPostTitle, body : 'Nouveau contenu du message' });
      setNewPostTitle('');
      setPostsData((prevData) => [newPost, ...prevData]);
      récupérer();
    }
  } ;

  // Mettre à jour un article existant et ajouter "HASAN" à son titre
  const handleUpdatePost = async (post) => {
    const { data : updatePost } = wait updatePost ({
      identifiant : post.id,
      titre : `${post.title} HASAN`,
    });
    setPostsData((prevData) =>
      prevData.map((item) => (item?.id === updatePost?.id ? updatePost : item))
    );
  } ;

  // Supprime une publication et la supprime immédiatement de l'interface utilisateur
  const handleDeletePost = async (id) => {
    attendre deletePost(id);
    setPostsData((prevData) => prevData.filter((post) => post.id !== id));
  } ;

  // Charge plus de messages pour un défilement infini
  const loadMorePosts = () => {
    si (!isFetching) {
      setPage((prevPage) => prevPage 1);
    }
  } ;

  // Basculer la visibilité modale
  const toggleModal = () => {
    setModalVisible(!isModalVisible);
  } ;

  if (isLoading && page === 1) return <Text>Loading...</Text>;
  if (isError) return <Text>Erreur lors de la récupération des publications.</Text>;

  retour (
    <SafeAreaView>



<ul>
<li>
<strong>Composant MainApp (src/MainApp.js)</strong> :

<ul>
<li>
<strong>State and Hooks</strong> : gère les états locaux (par exemple, pour la pagination des publications) et les hooks comme useLoginMutation pour déclencher des actions sur des événements spécifiques.</li>
<li>
<strong>Connexion</strong> :

<ul>
<li>Utilise useLoginMutation pour connecter l'utilisateur, puis déclenche refetchUserProfile pour charger les données du profil utilisateur.</li>
<li>
<em>Requête conditionnelle</em> : récupère le profil utilisateur uniquement lorsqu'un jeton valide existe (ignorer : !token), réduisant ainsi les appels d'API inutiles.</li>
</ul>


</li>

<li>

<strong>Récupération des messages</strong> :

<ul>
<li>Utilise useGetPostsQuery pour récupérer les publications paginées, prenant en charge le défilement infini en récupérant plus de données à mesure que l'utilisateur fait défiler.</li>
<li>
<em>Contrôle d'actualisation</em> : permet aux utilisateurs d'actualiser la liste des publications, utile pour la fonctionnalité d'extraction pour actualiser sur mobile.</li>
</ul>


</li>

<li>

<strong>Créer, mettre à jour, supprimer des publications</strong> :

<ul>
<li>
<em>Create</em> : appelle createPost, mettant immédiatement à jour la liste des publications avec la nouvelle publication en haut.</li>
<li>
<em>Mise à jour</em> : ajoute « HASAN » au titre d'un article lors de la mise à jour.</li>
<li>
<em>Supprimer</em> : supprime une publication et met à jour l'interface utilisateur sans avoir besoin de recharger la page, grâce à l'invalidation du cache de deletePost.</li>
</ul>


</li>

<li>

<strong>Éléments de l'interface utilisateur</strong> :

<ul>
<li>Un modal affiche le profil utilisateur. Le bouton de profil n'apparaît que si les données userProfile sont chargées, améliorant ainsi l'expérience utilisateur.</li>
</ul>


</li>

<li>

<strong>FlatList</strong> : affiche les publications dans un format défilant et paginé, améliorant ainsi la convivialité.</li>

</ul>

</li>

</ul>


<hr>

<h2>
  
  
  Résumé:
</h2>

<p>Votre application React Native utilise <strong>Redux Toolkit (RTK) Query</strong> pour une gestion efficace des données et des interactions API. La configuration comprend :</p>

<ol>
<li><p><strong>Configuration du magasin</strong> : magasin Redux avec redux-persist pour enregistrer des données spécifiques sur les sessions d'application, un middleware personnalisé pour la journalisation des erreurs et Reactotron pour le débogage en mode développement.</p></li>
<li>
<p><strong>API avec requête RTK</strong> :</p><ul>
<li>
<strong>authApi</strong> gère l'authentification avec une mutation de connexion, stockant le jeton dans Redux.</li>
<li>
<strong>postsApi</strong> fournit des opérations CRUD pour les publications, en utilisant des balises de cache pour actualiser automatiquement les données lorsque les publications sont ajoutées, mises à jour ou supprimées.</li>
<li>
<strong>usersApi</strong> récupère le profil utilisateur avec des en-têtes d'autorisation dynamiques basés sur des jetons.</li>
</ul>
</li>
<li><p><strong>Auth Slice</strong> : gère le jeton d'authentification et fournit des actions pour définir ou effacer le jeton lors de la connexion/déconnexion.</p></li>
<li>
<p><strong>Composants App et MainApp</strong> :</p>

<ul>
<li>L'application principale enveloppe les composants dans Provider et PersistGate, garantissant que l'état est chargé avant le rendu.</li>
<li>
MainApp gère la récupération, la création, la mise à jour et la suppression des publications. Il charge les données de manière conditionnelle (par exemple, récupère le profil utilisateur uniquement lorsqu'un jeton existe), prend en charge la pagination et le défilement infini </li>
<li>Utilise FlatList pour une liste de publications paginée, des modaux pour le profil et des styles de base pour une mise en page propre et organisée.</li>
</ul>
</li>
</ol>

<blockquote>
<p>CODE COMPLET->



          

            
        

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!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn