網站搜尋

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;