在本指南中,我們將介紹:
- CRUD 操作
- 分頁
- Redux 透過 RTK 查詢持久化
- 多個基本 URL 使用
- 受保護與公共路線
- 快取管理與失效
RTK 查詢 是內建於 Redux Toolkit (RTK) 中的進階資料擷取與快取工具。它透過為獲取、快取和更新資料等常見任務產生 Redux 切片和掛鉤來簡化 API 互動。主要功能包括:
- 自動快取:RTK Query 快取數據,並在數據失效時自動重新獲取,確保 UI 始終擁有最新數據。
- 快取失效:RTK 查詢使用標籤,讓您定義何時應重新取得某些資料。這有助於保持快取最新,無需手動更新資料。
- 自動產生的鉤子:RTK Query 為每個 API 端點建立鉤子,讓您可以使用簡單的 React 鉤子(useGetPostsQuery、useCreatePostMutation 等)呼叫 API。
- 錯誤處理:包括透過中間件的自訂錯誤處理,可以輕鬆捕獲和顯示錯誤。
- 簡化的 Redux 整合:RTK Query 直接與 Redux 集成,因此您不需要額外的函式庫來進行全域狀態管理或快取。
RTK 查詢與 React 查詢
React Query 和 RTK Query 都提供了 React 應用程式中的資料取得和快取解決方案,但它們具有不同的優勢和用例:
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. |
在 RTK 查詢和 React 查詢之間進行選擇:
-
使用 RTK 查詢如果:
- 您已經在使用 Redux,並且想要一個整合的、簡化的資料擷取解決方案。
- 您需要在 Redux 中進行集中式錯誤處理和開發工具整合。
-
使用 React 查詢 如果:
- 您想要一個更輕量級的設置,無需 Redux 依賴。
- 您喜歡單獨的伺服器狀態管理,不需要全域應用程式狀態。
本質上,RTK Query 非常適合以Redux 為中心的應用程序,而React Query 為沒有Redux 的專案或那些注重本地化伺服器狀態管理的專案提供了靈活性和簡單性。
1. 商店配置與設定
// 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):Redux store 是保存應用程式狀態的主要結構。在您的設定中,它透過 redux-persist 進行了增強,可以在本地保存 Redux 狀態的某些部分,因此即使應用程式重新啟動,它們也會持續存在。
-
redux-persist:
- 用途:幫助保持部分 Redux 狀態在應用程式會話中保持不變。
- 配置:persistConfig 物件指定 auth、postsApi 和 usersApi 不應被持久化(列入黑名單),這表示它們的資料會在應用程式重新啟動時重置。
- persistReducer 將減速器配置與持久化功能結合。
增強器:自訂增強器用於在開發模式下整合Reactotron,這是一個調試 Redux 操作、狀態和網路請求的有用工具。這只在開發時激活,使調試更容易,而不影響生產。
-
中介軟體:
- RTK 查詢中間件(postsApi.middleware、usersApi.middleware、authApi.middleware)新增自動快取管理功能,提升資料擷取效率。
- rtkQueryErrorLogger:自訂中間件在 API 呼叫失敗時記錄錯誤。它使用 RTK Query 的 isRejectedWithValue 函數來捕獲和處理錯誤,讓您可以提醒使用者有關問題或採取其他操作。
setupListeners:此功能可以在發生某些事件時自動重新獲取數據,例如當應用程式重新獲得焦點或從後台恢復時,為用戶提供新鮮數據,而無需手動重新整理.
2. RTK 查詢的 API 定義
RTK Query 透過自動產生 Redux 切片、掛鉤和快取來簡化 API 呼叫。以下是您定義的 API 的詳細資訊:
// 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):
- 定義登入突變,將使用者憑證(例如使用者名稱、密碼)傳送到伺服器進行身份驗證。
- onQueryStarted:登入成功後,它使用 setToken 操作將傳回的令牌儲存在 Redux 中。這可以實現對其他端點的安全性、經過身份驗證的請求。
// 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 操作:貼文 API 包含多個與貼文互動的端點(取得、建立、更新、刪除)。
- getPosts:獲取分頁帖子,這意味著它以較小的區塊(頁面)檢索數據,從而提高效能和載入時間。
- createPost、updatePost 和 deletePost:其中每一個都執行不同的操作(建立、更新或刪除貼文)。
- 用於快取的標籤:每個端點都使用標籤(例如,{ type: 'Posts', id })自動管理快取失效和刷新。例如,建立或刪除貼文會使快取失效,從而提示 getPosts 無需手動幹預即可取得新資料。
-
CRUD 操作:貼文 API 包含多個與貼文互動的端點(取得、建立、更新、刪除)。
// 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):
- 此 API 取得經過驗證的使用者的個人資料,根據 Redux 中的令牌設定授權標頭。
- Headers:prepareHeaders 動態地將令牌附加到每個請求(如果可用),從而允許安全且授權的 API 請求。
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:Redux 切片管理特定的狀態,在本例中為使用者驗證。
- 狀態管理:authSlice 保留使用者的令牌,用於存取受保護的 API 端點。
-
行動:
- setToken:在 Redux 狀態中儲存身份驗證令牌。
- logout:從 Redux 中清除令牌,有效地將使用者登出。
4. 用於調試的Reactotron (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 是一個偵錯工具,有助於追蹤 Redux 狀態變更、監控 API 請求和檢查日誌。
- Setup:配置為捕獲 console.log 輸出和 Redux 操作。在開發模式下,此設定提供了一種強大的調試方法,無需添加額外的程式碼或改變生產效能。
5. 主要應用元件
// 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;
-
應用程式元件(src/App.js):
- App 元件將整個應用程式包裝在 Provider(以使 Redux 可用)和 PersistGate(延遲渲染,直到檢索到持久狀態)。
- PersistGate 確保在應用程式顯示之前持久載入數據,減少載入時間不一致。
// src/MainApp.js 從 'react' 導入 React, { useEffect, useState }; 進口 { 活動指示器, 按鈕, 平面列表, 莫代爾, 刷新控制, 樣式表, 文字, 文字輸入, 看法, 來自 'react-native'; 從 'react-native-safe-area-context' 導入 { SafeAreaView } ; 從 'react-redux' 導入 { useDispatch, useSelector }; 從 './api/authApi' 導入 { useLoginMutation } ; 進口 { 使用CreatePostMutation, 使用DeletePostMutation, 使用GetPosts查詢, 使用LazyGetPosts查詢, 使用更新後突變, 來自 './api/postsApi'; 從'./api/usersApi'導入{useGetUserProfileQuery}; 導入{註銷}來自“./features/auth/authSlice”; const MainApp = () =>; { const [newPostTitle, setNewPostTitle] = useState(''); const [頁面,setPage] = useState(1); const [postsData, setPostsData] = useState([]); const [刷新,setRefreshing] = useState(false); const [isModalVisible, setModalVisible] = useState(false); const 調度 = useDispatch(); const token = useSelector((state) => state.auth.token); // 登入突變 const [login, { isLoading: isLoggingIn }] = useLoginMutation(); // 當令牌可用時取得使用者設定檔 const { 資料:userProfile,重新取得:refetchUserProfile } = useGetUserProfileQuery(未定義,{ 跳過:!令牌, }); // 取得分頁帖子 常量{ 數據:帖子, 正在加載, 正在獲取, 是錯誤, 重新獲取, } = useGetPostsQuery({ 頁數, 限制: 10 }); // 當你想在螢幕載入時取得資料時,使用 useQuery 鉤子。例如,在個人資料畫面上取得使用者個人資料。 // 使用惰性查詢刷新直接取得第1頁 const [triggerFetchFirstPage,{ 資料:lazyData }] = useLazyGetPostsQuery(); // useLazyquery 當你想要控制 api 呼叫時使用,例如按鈕點擊。 const [createPost] = useCreatePostMutation(); const [updatePost] = useUpdatePostMutation(); const [deletePost] = useDeletePostMutation(); useEffect(() => { 如果(帖子){ setPostsData((prevData) => (頁 === 1 ? posts : [...prevData, ...posts])); } }, [帖子, 頁]); // 登入處理程序 const handleLogin = async () =>; { 嘗試 { const 憑證 = { 使用者名稱:'emilys',密碼:'emilyspass' }; 等待登入(憑證); console.log('使用者設定檔', 使用者設定檔); 重新取得使用者設定檔(); } 捕獲(錯誤){ console.error('登入失敗:', error); } }; const handleRefresh = async () =>; { 設定刷新(真); 設定頁面(1); // 將頁面重設為 1 以進行下一個捲動 setPostsData([]); // 清除資料以避免重複 // 明確觸發第一頁獲取 const { 資料 } = 等待觸發FetchFirstPage({ 頁數: 1, 限制: 10 }); 如果(數據){ 設定貼文資料(資料); // 將貼文資料設定為第一頁的結果 } 設定刷新(假); }; // 建立一個新帖子,將其添加到頂部,然後重新獲取列表 const handleCreatePost = async () =>; { 如果(新帖子標題){ const { data: newPost } = wait createPost({ title: newPostTitle, body: '新帖子內容' }); 設定新貼文標題(''); setPostsData((prevData) => [newPost, ...prevData]); 重新獲取(); } }; // 更新現有貼文並將「HASAN」新增至其標題中 const handleUpdatePost = async (post) =>; { const { 資料:updatePost } = 等待 updatePost({ id:帖子id, 標題: `${post.title} HASAN`, }); setPostsData((prevData) =>; prevData.map((item) => (item?.id === UpdatedPost?.id ?updatedPost : item)) ); }; // 刪除貼文並立即將其從 UI 中刪除 const handleDeletePost = async (id) =>; { 等待deletePost(id); setPostsData((prevData) => prevData.filter((post) => post.id !== id)); }; // 加載更多帖子以實現無限滾動 const loadMorePosts = () =>; { if (!isFetching) { setPage((上一頁) => 上一頁 1); } }; // 切換模態可見性 consttoggleModal = () =>; { setModalVisible(!isModalVisible); }; if (isLoading && page === 1) return <text>正在載入...</text>; if (isError) return <text> 取得貼文時發生錯誤。 </text>; 返回 (
-
MainApp 元件 (src/MainApp.js):
- 狀態和掛鉤:管理本地狀態(例如,用於帖子分頁)和諸如 useLoginMutation 之類的掛鉤來觸發特定事件的操作。
-
登入:
- 使用 useLoginMutation 登入用戶,然後觸發 refetchUserProfile 載入用戶設定檔資料。
- 條件查詢:只有在有有效令牌時才取得使用者個人資料(跳過:!token),減少不必要的 API 呼叫。
-
取得貼文:
- 使用 useGetPostsQuery 獲取分頁帖子,透過在用戶滾動時獲取更多數據來支援無限滾動。
- 刷新控制項:允許用戶刷新貼文列表,對於行動裝置上的下拉式刷新功能很有用。
-
建立、更新、刪除貼文:
- Create:呼叫createPost,立即更新貼文列表,新貼文位於頂部。
- 更新:更新時將「HASAN」附加到貼文標題。
- 刪除:刪除貼文並更新 UI,無需重新載入頁面,這要歸功於 deletePost 的快取失效。
-
使用者介面元素:
- 模態顯示使用者個人資料。僅當載入使用者設定檔資料時才會出現設定檔按鈕,從而增強使用者體驗。
- FlatList:以可捲動、分頁格式顯示帖子,增強可用性。
概括:
您的 React Native 應用程式使用 Redux Toolkit (RTK) 查詢 來實現高效的資料管理和 API 互動。設定包括:
存儲配置:帶有redux-persist 的Redux 存儲,用於跨應用程序會話保存特定數據,用於錯誤日誌記錄的自定義中間件,以及用於在開發模式下進行偵錯的Reactotron。
-
有 RTK 查詢的 API:
- authApi 透過登入突變處理驗證,將令牌儲存在 Redux 中。
- postsApi 為貼文提供 CRUD 操作,在新增、更新或刪除貼文時使用快取標籤自動刷新資料。
- usersApi 使用基於動態令牌的授權標頭取得使用者設定檔。
Auth Slice:管理身分驗證令牌並提供在登入/登出時設定或清除令牌的操作。
-
應用程式和主應用程式元件:
- 主應用程式將元件包裝在 Provider 和 PersistGate 中,確保在渲染之前載入狀態。
- MainApp 管理貼文的取得、建立、更新和刪除。它有條件地載入資料(例如,僅當令牌存在時才取得使用者設定檔),支援分頁和無限滾動
- 使用 FlatList 作為分頁貼文列表,使用模式作為個人資料,並使用基本樣式來實現乾淨、有組織的佈局。
完整程式碼->
以上是透過 RTK 查詢在 React Native 中高效處理數據的詳細內容。更多資訊請關注PHP中文網其他相關文章!

JavaScript字符串替換方法詳解及常見問題解答 本文將探討兩種在JavaScript中替換字符串字符的方法:在JavaScript代碼內部替換和在網頁HTML內部替換。 在JavaScript代碼內部替換字符串 最直接的方法是使用replace()方法: str = str.replace("find","replace"); 該方法僅替換第一個匹配項。要替換所有匹配項,需使用正則表達式並添加全局標誌g: str = str.replace(/fi

本教程向您展示瞭如何將自定義的Google搜索API集成到您的博客或網站中,提供了比標準WordPress主題搜索功能更精緻的搜索體驗。 令人驚訝的是簡單!您將能夠將搜索限制為Y

因此,在這裡,您準備好了解所有稱為Ajax的東西。但是,到底是什麼? AJAX一詞是指用於創建動態,交互式Web內容的一系列寬鬆的技術。 Ajax一詞,最初由Jesse J創造

本文系列在2017年中期進行了最新信息和新示例。 在此JSON示例中,我們將研究如何使用JSON格式將簡單值存儲在文件中。 使用鍵值對符號,我們可以存儲任何類型的

利用輕鬆的網頁佈局:8 ESTISSEL插件jQuery大大簡化了網頁佈局。 本文重點介紹了簡化該過程的八個功能強大的JQuery插件,對於手動網站創建特別有用

核心要點 JavaScript 中的 this 通常指代“擁有”該方法的對象,但具體取決於函數的調用方式。 沒有當前對象時,this 指代全局對象。在 Web 瀏覽器中,它由 window 表示。 調用函數時,this 保持全局對象;但調用對象構造函數或其任何方法時,this 指代對象的實例。 可以使用 call()、apply() 和 bind() 等方法更改 this 的上下文。這些方法使用給定的 this 值和參數調用函數。 JavaScript 是一門優秀的編程語言。幾年前,這句話可

jQuery是一個很棒的JavaScript框架。但是,與任何圖書館一樣,有時有必要在引擎蓋下發現發生了什麼。也許是因為您正在追踪一個錯誤,或者只是對jQuery如何實現特定UI感到好奇

該帖子編寫了有用的作弊表,參考指南,快速食譜以及用於Android,BlackBerry和iPhone應用程序開發的代碼片段。 沒有開發人員應該沒有他們! 觸摸手勢參考指南(PDF)是Desig的寶貴資源


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

mPDF
mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

SublimeText3 英文版
推薦:為Win版本,支援程式碼提示!

Dreamweaver Mac版
視覺化網頁開發工具

Atom編輯器mac版下載
最受歡迎的的開源編輯器

禪工作室 13.0.1
強大的PHP整合開發環境