Skip to content

Feature Request: Return timestamp of last revalidation #1322

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

Closed
alii opened this issue Aug 1, 2021 Discussed in #802 · 3 comments
Closed

Feature Request: Return timestamp of last revalidation #1322

alii opened this issue Aug 1, 2021 Discussed in #802 · 3 comments
Labels
discussion Discussion around current or proposed behavior

Comments

@alii
Copy link

alii commented Aug 1, 2021

Discussed in #802

I'd like to have a go at tackling this, is there any guidance for people wanting to get started with the codebase? I've had a brief look through but not really figured out where/what would be the best thing to do here 😅

Cheers

Originally posted by alii December 10, 2020

For Example

import dayjs from 'dayjs';
import useSWR from 'swr';

export function Component() {
    const { timestamp: lastUpdated } = useSWR<User>("/users/@me");

    return <p>Last updated {dayjs(lastUpdated).fromNow()}</p>
}

Is this a good idea? Is this feasible?

@shuding
Copy link
Member

shuding commented Aug 1, 2021

I don't think this will be a widely needed feature. But you can attach the timestamp in your fetcher as a work around:

const fetcher = async (...args) => {
  const data = await fetchData(...args)
  return [data, Date.now()]
}

// ...
const { data: [data, lastUpdated] } = useSWR('/api', fetcher, {
  compare: (a, b) => deepCompare(a[0], b[0])
})

Note that you need to customize the compare function to avoid comparing the timestamp.

With the latest beta version, you can also create a middleware for it. Check #1160 for more details.

@shuding shuding added the discussion Discussion around current or proposed behavior label Aug 1, 2021
@shuding shuding closed this as completed Sep 6, 2021
@Armster15
Copy link

For others who had this need like me, you can also create a middleware (as shuding said above).
The middleware feature in SWR seems to be stable now and not in beta anymore so it should be safe to use.

Here's a working snippet that adds a fetchedAt property:

import { useEffect, useRef } from "react";
import { SWRConfig, Middleware, SWRHook } from "swr";

const fetchedAtMiddleware: Middleware = (useSWRNext: SWRHook) => {
  return (key, fetcher, config) => {
    const fetchedAtRef = useRef<Date | undefined>(undefined);

    useEffect(() => {
      const onSuccess = config.onSuccess;
      const onError = config.onError;

      config.onSuccess = (...args) => {
        fetchedAtRef.current = new Date();
        if (onSuccess) onSuccess(...args);
      };

      config.onError = (...args) => {
        fetchedAtRef.current = new Date();
        if (onError) onError(...args);
      };
    }, [config]);

    const swr = useSWRNext(key, fetcher, config);

    // After hook runs...
    return Object.assign({}, swr, {
      fetchedAt: fetchedAtRef.current,
    });
  };
};

Then you can use the middleware using SWRConfig:

<SWRConfig
    value={{
        use: [fetchedAtMiddleware]
        // ...
    }}
/>

And then you can use fetchedAt from any useSWR call:

const { data, error, fetchedAt } = useSWR("/api/hello");

Note that if you are using TypeScript, TypeScript will complain that the property fetchedAt doesn't exist on SWRResponse. To fix this, you can augment the types:

// https://github.com/vercel/swr/issues/1599#issuecomment-1287151974
declare module "swr" {
  interface SWRResponse {
    fetchedAt: Date | undefined;
  }
}

Hope this can help someone!

@raincoffeecode
Copy link

raincoffeecode commented Sep 23, 2024

@Armster15 thanks for sharing this!

I know this is from a while ago but is it better to use useState instead of useRef to force any components that use this value to re-render?

EDIT: Actually, even this doesn't work because it doesn't account for multiple components calling useSWR with the same key. I ended up implementing something with useSyncExternalStore and keeping track of the values externally.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
discussion Discussion around current or proposed behavior
Projects
None yet
Development

No branches or pull requests

4 participants