typescript - 嘗試在 React Native 的 Redux Toolkit 的 createApi 中合併 Cache 並同時使用 "invalidatesTags"
我嘗試在 "createApi" 中合併 "Cache" 並使用 "invalidatesTags",但只有一個能正常工作。
合併緩存運作正常,但在 DeleteCollection 中的 invalidatesTags 對 querySelect 返回的結果沒有可合併或刪除的項目。建立時也有相同問題,但我暫時已經修復它。
有人可以幫我嗎。非常感謝
這是我的 createApi:
import {createApi, fetchBaseQuery} from '@reduxjs/toolkit/query/react';
import config from '../../config.json';
const API_URL = config.API_URL;
const merchant = config.MERCHANT_NAME;
const store = config.STORE;
import {Collection} from '../../models/Collection.model';
interface ListResponse<T> {
offset: number;
count: number;
data: T[];
}
export const collectionApi = createApi({
reducerPath: 'collectionApi',
baseQuery: fetchBaseQuery({
baseUrl: `${API_URL}/merchants/${merchant}/stores/${store}/`,
}),
tagTypes: ['Collections'],
endpoints: builder => ({
getAllCollections: builder.query<ListResponse<Collection>, any>({
query: ({offset, limit}) => {
let filter = encodeURIComponent(
JSON.stringify({
offset: offset,
limit: limit,
}),
);
return {
url: `collections?filter=${filter}`,
};
},
providesTags: (result, error, page) => {
if (result) {
return [
...result.data.map(({id}) => ({type: 'Collections' as const, id})),
{type: 'Collections', id: 'PARTIAL-LIST'},
];
} else {
return [{type: 'Collections', id: 'PARTIAL-LIST'}];
}
},
serializeQueryArgs: ({queryArgs, endpointDefinition, endpointName}) => {
return endpointName;
},
merge: (currentCache, newItems) => {
if (newItems.offset == currentCache.offset) {
if (
newItems.count > currentCache.count &&
newItems.offset == currentCache.count
) {
currentCache.data = currentCache.data.concat(newItems.data);
} else if (currentCache.data == null) {
currentCache.data = newItems.data;
}
currentCache.offset = newItems.offset;
currentCache.count = newItems.count;
} else if (newItems.offset > currentCache.offset) {
currentCache.data = currentCache.data.concat(newItems.data);
currentCache.offset = newItems.offset;
currentCache.count = newItems.count;
}
},
forceRefetch({currentArg, previousArg}) {
return currentArg !== previousArg;
},
}),
createCollection: builder.mutation<Collection, Partial<any>>({
query: data => ({
url: `collections/`,
method: 'POST',
body: data,
}),
invalidatesTags: (result, error, data) => {
return [
{type: 'Collections', id: result?.id},
{type: 'Collections', id: 'PARTIAL-LIST'},
];
},
}),
updateCollection: builder.mutation<Collection, Partial<any>>({
query: ({data, id}) => ({
url: `collections/${id}`,
method: 'PATCH',
body: data,
}),
invalidatesTags: (result, error, {id}) => [
{type: 'Collections', id},
{type: 'Collections', id: 'PARTIAL-LIST'},
],
}),
deleteCollection: builder.mutation<{success: boolean; id: number}, number>({
query: id => ({
url: `collections/${id}`,
method: 'DELETE',
}),
invalidatesTags: (result, error, id) => [
{type: 'Collections', id},
{type: 'Collections', id: 'PARTIAL-LIST'},
],
}),
}),
});
// Export hooks for usage in functional components
export const {
useGetAllCollectionsQuery,
useCreateCollectionMutation,
useUpdateCollectionMutation,
useDeleteCollectionMutation,
} = collectionApi;
這是我使用的地方:
import React, {useEffect} from 'react';
import {
ActivityIndicator,
Alert,
Image,
StyleSheet,
Text,
TouchableOpacity,
View,
} from 'react-native';
import {FlatList} from 'react-native-bidirectional-infinite-scroll';
import ButtonSmall from '../../components/ButtonSmall';
import theme from '../../core/theme';
import {Icon} from '@rneui/themed';
import {
useCreateCollectionMutation,
useDeleteCollectionMutation,
useGetAllCollectionsQuery,
} from '../../redux/services/collection';
const CollectionManagement = ({navigation}: any) => {
//for infinite scroll
const [offset, setOffset] = React.useState(0);
const [limit, setLimit] = React.useState(10);
//get collection
const {
data: allCollectionsData,
error,
isError,
isLoading,
refetch,
} = useGetAllCollectionsQuery({offset: offset, limit: limit});
const onStartReached = async () => {
// console.log('reload');
// await setOffset(0);
// await refetch();
return;
};
const onEndReached = async () => {
if (allCollectionsData) {
if (offset + limit > allCollectionsData.count) {
await setOffset(allCollectionsData.count);
} else {
await setOffset(offset + limit);
}
} else {
await setOffset(offset + limit);
}
await refetch();
return;
};
//end infinite scroll
const total = allCollectionsData?.count;
const collectionList = allCollectionsData?.data;
//delete collection
const [
deleteCollection,
{data: dataDelete, error: errorDelete, isSuccess: isSuccessDelete},
] = useDeleteCollectionMutation();
//create collection
const [
createCollection,
{data: dataCreate, error: errorCreate, isSuccess: isSuccessCreate},
] = useCreateCollectionMutation();
const deleteCollectionHandle = (id: any) => {
Alert.alert('Thông báo', 'Bạn có chắc chắn muốn xoá danh mục này?', [
{
text: 'Không',
onPress: () => {},
},
{
text: 'Có',
onPress: () => {
deleteCollection(id);
},
},
]);
};
const doubleCollection = (data: any) => {
let newData = {
name: data.name,
position: Number(data.position),
description: data.description,
internalName: data.internalName,
};
createCollection(newData);
};
return (
<View style={styles.container}>
<View style={styles.header}>
<Text style={styles.title}>Danh sách danh mục</Text>
<Text style={styles.total}>Tổng số bản ghi: {total} </Text>
<ButtonSmall
title="Thêm mới"
onPress={() => {
navigation.navigate('CollectionCreate');
}}
/>
</View>
<View style={styles.body}>
{isLoading ? (
<View
style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<ActivityIndicator size="large" />
</View>
) : (
<FlatList
data={collectionList}
onEndReached={onEndReached}
onStartReached={onStartReached}
keyExtractor={(item: any) => item.id}
renderItem={(data: any) => {
let item = data.item;
let url = item.preview;
if (url === '') {
url = 'https://petitemaika.com/brand.png';
}
return (
<View key={item.id} style={styles.item}>
<View style={styles.info}>
<Image source={{uri: url}} style={styles.image} />
<View style={styles.detail}>
<Text
style={styles.itemName}
ellipsizeMode="middle"
numberOfLines={2}>
{item.name}
</Text>
<Text
style={styles.itemName}
ellipsizeMode="middle"
numberOfLines={1}>
Tên rút gọn: {item.internalName}
</Text>
<Text
style={styles.itemName}
ellipsizeMode="middle"
numberOfLines={3}>
Mô tả: {item.description}
</Text>
<Text
style={styles.itemName}
ellipsizeMode="middle"
numberOfLines={2}>
Thứ tự: {item.position}
</Text>
</View>
</View>
<View style={styles.action}>
<TouchableOpacity
onPress={() => {
navigation.navigate('CollectionEdit', item);
}}>
<View style={styles.button}>
<Text style={styles.buttonText}>Sửa</Text>
<Icon
name="pencil"
type="ionicon"
color={'white'}
size={20}
/>
</View>
</TouchableOpacity>
<TouchableOpacity
onPress={() => {
doubleCollection(item);
}}>
<View style={styles.button}>
<Text style={styles.buttonText}>Nhân bản</Text>
<Icon
name="copy"
type="ionicon"
color={'white'}
size={20}
/>
</View>
</TouchableOpacity>
<TouchableOpacity
onPress={() => {
deleteCollectionHandle(item.id);
}}>
<View style={styles.button}>
<Text style={styles.buttonText}>Xoá</Text>
<Icon
name="trash"
type="ionicon"
color={'white'}
size={20}
/>
</View>
</TouchableOpacity>
</View>
</View>
);
}}
/>
)}
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
},
header: {
flex: 2,
backgroundColor: theme.colors.BACKGROUND,
justifyContent: 'space-between',
alignItems: 'center',
padding: 5,
},
body: {
flex: 8,
backgroundColor: theme.colors.BACKGROUND,
},
//text styles
title: {
fontSize: 20,
fontWeight: 'bold',
color: theme.colors.BLACK,
},
total: {
fontSize: 16,
color: theme.colors.BLACK,
},
itemName: {
fontSize: 16,
color: theme.colors.BLACK,
},
//collection styles
item: {
flex: 1,
margin: 10,
borderColor: theme.colors.GREY,
borderWidth: 1,
borderRadius: 10,
padding: 10,
flexDirection: 'column',
justifyContent: 'space-between',
},
info: {
flexDirection: 'row',
flex: 1,
},
action: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'flex-end',
flex: 1,
marginTop: 10,
},
image: {
width: 100,
height: 100,
borderRadius: 10,
marginEnd: 10,
},
button: {
backgroundColor: theme.colors.PRIMARY,
borderRadius: 7,
alignItems: 'center',
justifyContent: 'center',
paddingVertical: 3,
paddingHorizontal: 10,
flexDirection: 'row',
},
buttonText: {
fontSize: 14,
fontWeight: 'bold',
color: theme.colors.WHITE,
marginEnd: 5,
},
detail: {
flex: 1,
flexDirection: 'column',
},
});
export default CollectionManagement;