swr icon indicating copy to clipboard operation
swr copied to clipboard

The type and runtime behavior of `mutate/trigger` fn are mismatched

Open promer94 opened this issue 1 year ago • 1 comments

Problem

The runtime behavior of mutate/trigger is complex and the current type does not correctly match the actual behavior.

mutate('/key', fetcher, { populateCache: true, revalidate: true }) // -> return revalidation result
mutate('/key', fetcher, { populateCache: true, revalidate: false }) // -> return fetcher result
mutate('/key', fetcher, { populateCache: () => Data, revalidate: true }) // -> return revalidation result
mutate('/key', fetcher, { populateCache: () => Data, revalidate: false }) // -> return Data
mutate('/key', fetcher, { populateCache: false, revalidate: true }) // -> return fetcher result
mutate('/key', fetcher, { populateCache: false, revalidate: false }) // -> return fetcher result

related issues

#2647 #2661

promer94 avatar Jun 24 '23 13:06 promer94

I also got this issue. @promer94 What do you think should be the correct behavior of mutate/trigger? I suggest it always return the fetcher's result, undefined if fetcher isn't provided, because sometimes we have to mutate local data in a chain.

For example, in an IM app, when user sends a new message to a conversation, we need to insert this message to local message list and update the corresponding conversation's latest message. I'm not sure if the following is the best practice, anyway it's our current way:

export function useSendMessage(conversationId:string, message: string) {
    const insertMessage: () => Promise<Message> = () => {
           // promise that insert message through a post request
    }
    const {trigger: triggerMessages} = useSWRMutation<Message[]>(MESSAGGS_KEY_OF(conversationId), post, {
        populateCache(result, currentData) => {
              // the first issue here, type mismatched, 
              // mutate/trigger expects the fetcher's response type the same as the existing data,
              // which is not always true
              const insertedMessage = result as unknown as Message
              return [message, ...currentData]
        }
    })
    return useSWRMutation<Conversation[]>(CONVERSATIONS_KEY, () => triggerMessages(), {
        populacateCache(result, currentData) => {
            // the second issue here, the triggerMessages() sometimes returns Message, 
            // sometimes returns Message[], depending on values of populateCache and revalidate
            const insertedMessage = result[0]
            // in some other case, it should be 
            // const insertedMessage = result


            // update conversations then return
         }
    })
}

Ponyets avatar Jul 10 '23 06:07 Ponyets