0

I have the following piece of code:

function MyApp({ Component, pageProps }: AppProps) {
    const { tronLinkAuth, tronLinkLoading, mutateTronLink } = useTronLink();
    const { authenticatedUser, authLoading, authLoggedOut, mutateAuth } = useAuthenticatedUser();

    return (
        <React.StrictMode>
            <CSSReset />
            <ColorModeScript initialColorMode={theme.config.initialColorMode} />
            <ChakraProvider theme={theme}>
                <AuthenticationContext.Provider value={{
                    tronLinkAuth, tronLinkLoading, mutateTronLink,
                    authenticatedUser, authLoading, authLoggedOut, mutateAuth
                }}>
                    <Component {...pageProps} />
                </AuthenticationContext.Provider>
            </ChakraProvider>
        </React.StrictMode>
    )
}

Example useAuthenticatedUser:

export default function useAuthenticatedUser() {
    const { data, mutate, error } = useSWR("api_user", fetcher, {
        errorRetryCount: 0
    });

    const loading = !data && !error;
    const loggedOut = error && error instanceof UnauthorizedException;

    return {
        authLoading: loading,
        authLoggedOut: loggedOut,
        authenticatedUser: data as AuthenticatedUser,
        mutateAuth: mutate
    };

}

The code works, but my entire webpage gets re-rendered when swr propagates its result.

For example:

const Login: NextPage = () => {
    console.log('login update');
    return (
        <>
            <Head>
                <title>Register / Login</title>
            </Head>
            <Navbar />
            <Box h='100vh'>
                <Hero />
            </Box>
            <Box h='100vh' pt='50px'>
                Test second page
            </Box>
        </>
    )
}

export default Login;

When using useContext in the Navbar, it also re-renders the entire LoginPage, including the Hero, while this is not my purpose.

const Navbar: React.FC = () => {
    const authState = useContext(AuthenticationContext);
    ... 

I'm also confused as for why the logs appear in the server console, as this is supposed to be executed client-side.
Edit: not an issue, this is only on first render.

How to solve?

I'm interested in using swr for this use case, because it allows me to re-verify the authentication status e.g. on focus but use the cached data meanwhile.

Edit: Confusing. The following log:

function MyApp({ Component, pageProps }: AppProps) {
    console.log('app');
    const { tronLinkAuth, tronLinkLoading, mutateTronLink } = useTronLink();
    const { authenticatedUser, authLoading, authLoggedOut, mutateAuth } = useAuthenticatedUser();

Also gets printed out every time I switch tabs and activate the swr.
So it re-renders the entire tree? Doesn't seem desirable...

html_programmer
  • 18,126
  • 18
  • 85
  • 158

1 Answers1

0

I currently went with the easier solution, i.e. use useSwr immediately on the component that uses the data.

From the docs:

Each component has a useSWR hook inside. Since they have the same SWR key and are rendered at the almost same time, only 1 network request will be made.

You can reuse your data hooks (like useUser in the example above) everywhere, without worrying about performance or duplicated requests.

So it can be leveraged to re-use it wherever needed without having to worry about global state re-renders.
In case there is an alternative response how to use the global Context Provider, don't hesitate to share.

html_programmer
  • 18,126
  • 18
  • 85
  • 158
  • 1
    this is exactly the same approach I used in one of my apps, I have a useSwr hook in each of my components knowing that due to the key, in your case api_user, the useSwr hook will always first check the cache to see if user is available, if yes, then it'll return that user and will always then make a network call to get user via the fetcher. The only other improvement I could think of is adding a revalidateOnFocus to true. This way if your user walks away for a few minutes then returns then when the window again gets focus a network request will be made to get the user. – Sangeet Agarwal Dec 09 '21 at 21:12