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

Next.JS example is not wrapped with a Provider - is it intended? #1272

Closed
LunarMelody opened this issue Jul 6, 2022 · 13 comments
Closed

Next.JS example is not wrapped with a Provider - is it intended? #1272

LunarMelody opened this issue Jul 6, 2022 · 13 comments

Comments

@LunarMelody
Copy link

LunarMelody commented Jul 6, 2022

Hello! I was switching from Vue and had a need for some state management, so I tried Jotai and really enjoy it so far ❤️

The only thing that is a little bit unclear for me is the use of Provider. I have read the discussion in #1207 and related issues, and it seems like Provider is extremely necessarily for SSR / SSG (correct me if I am wrong about it actually).

So I thought if the Provider wrapper component that important, then maybe NextJS example should be updated as well? The example's app isn't wrapped with Provider and it's index page seems to be using SSR, which is a little bit confusing then 😅

@dai-shi
Copy link
Member

dai-shi commented Jul 6, 2022

Yeah, it's better to have it for SSR. It's why jotai is Context based.
@Thisen Will you confirm and update the example?

@Thisen
Copy link
Collaborator

Thisen commented Jul 7, 2022

I'll update the example 👍🏼

@Thisen
Copy link
Collaborator

Thisen commented Jul 7, 2022

vercel/next.js#38398

@LunarMelody
Copy link
Author

Yeah, it's better to have it for SSR. It's why jotai is Context based. @Thisen Will you confirm and update the example?

Alright, thanks for the clarification! By the way. documentation examples might need an update as well 😄

@GoldStrikeArch
Copy link

GoldStrikeArch commented Jul 7, 2022

Yeah, it's better to have it for SSR. It's why jotai is Context based. @Thisen Will you confirm and update the example?

Isn't there already an example with useHydrateAtoms and without provider?

#340 (comment)

Is it too old and outdated? @Thisen

@Thisen
Copy link
Collaborator

Thisen commented Jul 8, 2022

No, useHydrateAtoms behavior hasn't changed 😄

@GoldStrikeArch
Copy link

GoldStrikeArch commented Jul 8, 2022

No, useHydrateAtoms behavior hasn't changed 😄

So, what is the "recommended" way then? useHydrateAtoms or Provider (or both) inside _app.tsx?

@Thisen

@LunarMelody
Copy link
Author

No, useHydrateAtoms behavior hasn't changed smile

So, what is the "recommended" way then? useHydrateAtoms or Provider (or both) inside _app.tsx?

@Thisen

Yeah, actually the more I try to understand the more confused I am 😄

I have noticed we can provide initialValues to the Provider component, is it essentially the same as if I were to apply useHydrateAtoms and the Provider but without passing anything to initialValues of the Provider? Currently I am hydrating all my atoms inside _app.tsx and I am also wrapping root element with Provider. So from my understanding it's possible to avoid use of useHydrateAtoms completely with Provider by passing initialValues to it, is it correct?

If it's possible, then I wonder if passing initialValues to the Provider make some conflict with useHydrateAtoms hook? 🤔

@Thisen
Copy link
Collaborator

Thisen commented Jul 11, 2022

No, useHydrateAtoms behavior hasn't changed 😄

So, what is the "recommended" way then? useHydrateAtoms or Provider (or both) inside _app.tsx?

@Thisen

I'd say that wrapping your app in a Provider is recommended for the reasons stated in #1207. useHydrateAtoms is optional, however very convenient, because it allows you to keep atoms module specific.

Lets say you have a CounterPage in a Next.js app, where you get the initialCount from the server, then this allows you to do this:

import { atom, useAtom } from 'jotai'
import { useHydrateAtoms } from 'jotai/utils'

const countAtom = atom(0)
const CounterPage = ({ countFromServer }) => {
  useHydrateAtoms([[countAtom, countFromServer]])
  const [count] = useAtom(countAtom)
  // count would be the value of `countFromServer`, not 0.
}

This has the following benefits:

  • It allows the atom to stay module-specific and you don't need to export it and see initialValues in app.tsx
  • useHydrateAtoms makes sure the atom only hydrates once.

I hope this is helpful @MihailPertsev and @TenkoSpirit.

@GoldStrikeArch
Copy link

GoldStrikeArch commented Jul 11, 2022

@Thisen

Ok, so we still need to wrap our _app.tsx in Provider.
If I also have QueryClientProvider from react-query there, then should Provider from jotai be the first one or the second one?

Is this one correct?

const MyApp = function MyApp({ Component, pageProps }) {
    const [queryClient] = useState(() => new QueryClient());


    return (
        <QueryClientProvider client={queryClient}>
            <Hydrate state={pageProps.dehydratedState}>
             <JotaiProvider>
                  <Component {...pageProps} />  
              </JotaiProvider>
            </Hydrate>
            <ReactQueryDevtools initialIsOpen={false} />
        </QueryClientProvider>
    );
};

Or that one:

const MyApp = function MyApp({ Component, pageProps }) {
    const [queryClient] = useState(() => new QueryClient());


    return (
    <JotaiProvider>
        <QueryClientProvider client={queryClient}>
            <Hydrate state={pageProps.dehydratedState}>
          
                  <Component {...pageProps} />  
         
            </Hydrate>
            <ReactQueryDevtools initialIsOpen={false} />
        </QueryClientProvider>
     </JotaiProvider>
    );
};

@Thisen
Copy link
Collaborator

Thisen commented Jul 11, 2022

@Thisen

Ok, so we still need to wrap our _app.tsx in Provider. If I also have QueryClientProvider from react-query there, then should Provider from jotai be the first one or the second one?

Is this one correct?

const MyApp = function MyApp({ Component, pageProps }) {
    const [queryClient] = useState(() => new QueryClient());


    return (
        <QueryClientProvider client={queryClient}>
            <Hydrate state={pageProps.dehydratedState}>
             <JotaiProvider>
                  <Component {...pageProps} />  
              </JotaiProvider>
            </Hydrate>
            <ReactQueryDevtools initialIsOpen={false} />
        </QueryClientProvider>
    );
};

Or that one:

const MyApp = function MyApp({ Component, pageProps }) {
    const [queryClient] = useState(() => new QueryClient());


    return (
    <JotaiProvider>
        <QueryClientProvider client={queryClient}>
            <Hydrate state={pageProps.dehydratedState}>
          
                  <Component {...pageProps} />  
         
            </Hydrate>
            <ReactQueryDevtools initialIsOpen={false} />
        </QueryClientProvider>
     </JotaiProvider>
    );
};

The first one. Then you can use the common queryClient if you choose to use atomWithQuery.

@LunarMelody
Copy link
Author

No, useHydrateAtoms behavior hasn't changed 😄

So, what is the "recommended" way then? useHydrateAtoms or Provider (or both) inside _app.tsx?
@Thisen

I'd say that wrapping your app in a Provider is recommended for the reasons stated in #1207. useHydrateAtoms is optional, however very convenient, because it allows you to keep atoms module specific.

Lets say you have a CounterPage in a Next.js app, where you get the initialCount from the server, then this allows you to do this:

import { atom, useAtom } from 'jotai'
import { useHydrateAtoms } from 'jotai/utils'

const countAtom = atom(0)
const CounterPage = ({ countFromServer }) => {
  useHydrateAtoms([[countAtom, countFromServer]])
  const [count] = useAtom(countAtom)
  // count would be the value of `countFromServer`, not 0.
}

This has the following benefits:

  • It allows the atom to stay module-specific and you don't need to export it and see initialValues in app.tsx
  • useHydrateAtoms makes sure the atom only hydrates once.

I hope this is helpful @MihailPertsev and @TenkoSpirit.

Alright, so basically the hydration hook isn't exactly required but can be very useful. I actually have a good use case for this hook in my project then! Thanks a lot for the explanation and your time ❤️

@Thisen
Copy link
Collaborator

Thisen commented Jul 11, 2022

No problem! Closing this :)

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

4 participants