Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to call write-only atom in mutationFn? #80

Open
StringKe opened this issue May 6, 2024 · 1 comment
Open

How to call write-only atom in mutationFn? #80

StringKe opened this issue May 6, 2024 · 1 comment

Comments

@StringKe
Copy link

StringKe commented May 6, 2024

I need to reset the cache for some query after mutationFn finishes so that the query is re-requested.

I'm using bunshi for wrapping and I've found that I can't fulfill this requirement, I can't directly dispatch any hooks like useSetAtom in bunshi's molecule.

In my code _resetIndex and _reset appear several times, in my conception I should have called resetDetailFolderPageAtom at mutationFn.

I'm not quite sure if this issuse belongs to bunshi or jotai or jotai-tanstack-query, if it doesn't belong to jotai-tanstack-query I can move it to another repository.

import { ComponentScope, molecule } from 'bunshi';
import { atom, type Getter, type WritableAtom } from 'jotai';
import { atomWithInfiniteQuery, atomWithMutation, atomWithQuery } from 'jotai-tanstack-query';

import api, { type ResourceId } from '~/api';
import { getQueryClient } from '~/lib/constants';

export const UploadMolecule = molecule((_mol, scope) => {
    scope(ComponentScope);

    const resourceType = atom<'resource' | 'design'>('resource');
    const filterAtom = atom<'all' | 'svg' | 'image'>('all');
    const folderIdAtom = atom<ResourceId>('');

    const _resetIndex = () => {
        void getQueryClient().refetchQueries({
            queryKey: ['user-folders', 'resource'],
        });
    };
    const _reset = (get: Getter) => {
        void getQueryClient().setQueryData(['user-folder-detail', get(folderIdAtom), get(resourceType)], () => ({
            pages: [],
            pageParams: 0,
        }));
        void getQueryClient().refetchQueries({
            queryKey: ['user-folder-detail', get(folderIdAtom), get(resourceType)],
        });
    };

    const resetDetailFolderPageAtom = atom(null, (get) => {
        _reset(get);
    });

    // 新增用户上传资源文件夹
    const folderCreateAtom = atomWithMutation(
        (get) => ({
            mutationKey: ['user-create-folder'],
            mutationFn: async ({ name }: { name: string }) => {
                const dataResponse = await api.user.folder.create({}, get(resourceType), name);
                _resetIndex();
                return dataResponse!;
            },
        }),
        getQueryClient,
    );

    // 修改用户上传资源文件夹
    const folderUpdateAtom = atomWithMutation(
        () => ({
            mutationKey: ['user-update-folder'],
            mutationFn: async ({ id, name }: { id: string; name: string }) => {
                const dataResponse = await api.user.folder.update({}, id, name);
                _resetIndex();
                return dataResponse!;
            },
        }),
        getQueryClient,
    );

    // 删除用户上传资源文件夹
    const folderDeleteAtom = atomWithMutation(
        () => ({
            mutationKey: ['user-delete-folder'],
            mutationFn: async ({ id }: { id: string }) => {
                const dataResponse = await api.user.folder.delete({}, id);
                _resetIndex();
                return dataResponse!;
            },
        }),
        getQueryClient,
    );

    // 移动用户上传资源文件夹
    const detailMoveAtom = atomWithMutation(
        (get) => ({
            mutationKey: ['user-move-detail'],
            mutationFn: async ({ targetId, sourceIds }: { targetId: string; sourceIds: string[] }) => {
                const dataResponse = await api.user.folder.moveItems({}, targetId, sourceIds);
                _reset(get);
                return dataResponse!;
            },
        }),
        getQueryClient,
    );

    // 删除用户上传的资源
    const detailDeleteAtom = atomWithMutation(
        (get) => ({
            mutationKey: ['user-delete-detail'],
            mutationFn: async ({ id }: { id: string }) => {
                const dataResponse = await api.user.resource.delete({}, id);
                _reset(get);
                return dataResponse!;
            },
        }),
        getQueryClient,
    );

    const foldersQueryAtom = atomWithQuery(
        (get) => ({
            queryKey: ['user-folders', 'resource'],
            queryFn: async () => {
                return await api.user.folder.all({}, get(resourceType));
            },
        }),
        getQueryClient,
    );

    const detailFolderAtom = atomWithInfiniteQuery(
        (get) => ({
            initialPageParam: 1,
            queryKey: ['user-folder-detail', get(folderIdAtom), get(resourceType)],
            queryFn: async ({ pageParam }) => {
                return await api.user.folder.items(
                    {
                        params: {
                            page: pageParam,
                            filter: get(filterAtom),
                        },
                    },
                    get(resourceType),
                    get(folderIdAtom),
                );
            },
            getNextPageParam: (lastPage) => {
                if (lastPage?.nextPage >= lastPage?.pages) return undefined;
                return lastPage?.nextPage;
            },
        }),
        getQueryClient,
    );

    return {
        resourceType,
        detailMoveAtom,
        detailDeleteAtom,
        folderCreateAtom,
        folderUpdateAtom,
        folderDeleteAtom,
        filterAtom,
        folderIdAtom,
        foldersQueryAtom,
        detailFolderAtom,
        resetDetailFolderPageAtom: resetDetailFolderPageAtom as WritableAtom<null, [], void>,
    };
});
@kalijonn
Copy link
Collaborator

Whenever I need to invalidate queries, I typically do it in the onSuccess section of a mutation.

const postAtom = atomWithMutation((get) => ({
  mutationKey: ['posts'],
  mutationFn: async ({ title }: { title: string }) => {
    const res = await fetch(`https://jsonplaceholder.typicode.com/posts`, {
      method: 'POST',
      body: JSON.stringify({
        title,
        body: 'body',
        userId: 1,
      }),
      headers: {
        'Content-type': 'application/json; charset=UTF-8',
      },
    })
    const data = await res.json()
    return data
  },
  onSuccess: () => {
    const client = get(queryClientAtom)

    client.invalidateQueries({ queryKey: ['posts'] })
  },

not sure if this helps but I can look further if you can create a minimal repo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants