Closed adamjedlicka closed 1 year ago
That is an issue for sure. One easy way to mitigate it would be to reset the store in the root app layout.
In the scenario I was thinking about, e-Commerce, the pages I was thinking about (product detail, search, home) don't have customer specific data so leakage would amount to a simple bug.
Resetting the store isn't a proper fix, because there is a second more sinister issue. And thats race condition. If you have multiple users accessing your site at the same time, Next server handles all of them "in parallel". This means that if first user requests some category filtered by colour, and another user requests the same category but unfiltered (rendering happens in the same page component), they might get nonsense results based on which network requests finishes first (unfiltered finishes first because it was cached, so the user who requested filtered category will also receive unfiltered).
To me, this seems like it it same as just storing data to global variable (global.state = XXX), which is immediately recognized as a bad idea.
I don't disagree that globals are bad. But we've been using global state for a long time, Redux in particular, and folks wanted to know how to use it in the NextJS 13 context. Yes there are pitfalls. It's not clear to me that this is 100% an issue because serverless functions handle one request at a time. But if folks think that is an issue they can block until all requests are completed at the top level, then let the render go.
This isn't critique of global state, but that because server components don't have access to context, you are accessing state shared between requests, which in development looks fine because you are the only user but it will most likely cause trouble in the production with multiple concurrent users.
Good point with the server-less though. It might not be a problem there, but in traditional Node.js production environment, it certainly will be for non-trivial apps.
I'll add some warnings and caveats to a README.
This was an initial frustration for me as well with the app directory. But thanks to Node async context (which is how React cache() works) you can in fact gain access to the per user request context. So to fix it with Redux, it should be aa simple as
const store = React.cache(() => configureStore(...))
Edit: make sure to not wrap the store with cache on the client (maybe conditionaly test for window).
Awesome!!!! I didn't know that was out. Thank you so much for the tip! If I do an update on this I'll give you a shout out!
Obviously test that it works with Redux's store, but I'm using the same idea successfully with fetch-cache (with tests that count cache size from different requests). This video was a big help:
https://www.youtube.com/watch?v=h7tur48JSaw
It's long and... interesting.. but some good info from Dan Abramov about RSCs and at one point (I think around 45 mins in) they talk about how RSC server context works. I think the only way we have access to it in Next is through React's cache though, and I assume Next.js instantiates it when they start the server.
Cool. Thanks for the tip, I gotta check it out 🙂
I just realized that React Server Components exposes server-side programming to a huge amount of programmers that have no idea about server-side programming ... ... programming RSC without concepts like session-scope and request-scope is going to be challenging ...
In my opinion, advising to use "global state" on the server is very dangerous. I think it is a bad idea to use redux on the server ... The very idea of the redux store is, that you have long-lived state per user that changes over time . On the server you do either not have long-lived state: request-response is inherently stateless. Or you might have global state (like the setup in the example repository) that probably should not change in the sense of "actions" which are manipulating the state ... (the third option would involve a http-session, if the redux store could be scoped to the session, then this might make the most sense for me ... but http-session opens another can of worms ...)
Serverless might avoid problems when programmers are not differentiating global-scope and request-scope, since the global scope could be recreated on every request ... but I would not bet on it, I think serverless platforms (I have not much experience with serverless) could well "optimize" and "reuse" functions ...
I think this is something they're still working out, but you can have per request state. See https://beta.nextjs.org/docs/data-fetching/caching#per-request-caching. Behind the scenes, they using this "request state" for that and for their fetch deduping.
I'm pretty sure this is new and we're all learning here, but what's wrong with Redux on the server in general? I've used it for years and so have many others without problem. In my opinion at least, the pitfall of global (not request safe) state is backend 101 if you're going to be writing async code that runs on a server. Doesn't really matter the environment. If you're in Express.js, referencing a var anywhere above route handler/middleware scope will put you in global land. Same thing can apply to serverless if the function is still warm. You might want this to keep a database connection alive, for example.
That said, I'm not totally clear on what happens with RSCs when you refresh (Router.refresh()). My current RSC project is mostly read only so I haven't needed to play with mutations. Does it refresh the entire page/route or just call the child RSC(S) in isolation? Either way, it would seem like all the busy work of instanitating the full store just for a mutation/update would be overkill. On the page/route level though, I've found it to be a nice way of avoiding prop drilling, while also being more or less isomorphic with the client.
Personally, so far I'm not really sold on RSCs or really frameworks in general but that's another story. Having this be proprietary React doesn't feel future proof, and for static/content heavy, islands seem like a better choice. One thing is certain... hosters that bill by request/time are sure to benefit.
i am using redux like this and i want to know that does we have to use redux always like thisimport HomeComponent from "@/components/Home"; import Preloader from "@/components/Preloader"; import { ThemeSwitch } from "@/components/Utilities/theme-switch"; import { GetAllProductsDocument } from "@/graphql/generated/schema"; import { getClient } from "@/lib/client"; import { setProducts } from "@/redux/slices/productSlice"; import { store } from "@/redux/store";
import { Product } from "@/types/product"; export const dynamic = "force-dynamic";
export const getAllProducts = async () => { const { data } = await getClient().query<{ getAllProducts: Product[] }>({ query: GetAllProductsDocument, });
return data?.getAllProducts; };
export default async function Home() { const data = await getAllProducts(); store.dispatch(setProducts(data)); return ( <>
<ThemeSwitch />
<HomeComponent />
</>
); } to store the data into redux from server
@jherr is the way we are using the redux in nextjs13 is will be always or it will change in future i am making projects using apollo client and redux literally i get frustated and think to leave react community.because all the libraries are in beta
I don't advise that folks use the code in this repo. For a much better and well tested set of patterns follow the tutorial here: https://www.pronextjs.dev/tutorials/state-management
Hey jack i want to talk with you because i get stuck in nextjs13 i just need may be 5 minutes can you help
On Sun, 15 Oct 2023 at 18:51, Jack Herrington @.***> wrote:
Closed #2 https://github.com/jherr/nextjs13-pokemon/issues/2 as completed.
— Reply to this email directly, view it on GitHub https://github.com/jherr/nextjs13-pokemon/issues/2#event-10657625652, or unsubscribe https://github.com/notifications/unsubscribe-auth/A6P7ZXVRAY4DQ5GEOOTORIDX7PNV7ANCNFSM6AAAAAAV45XLIE . You are receiving this because you commented.Message ID: @.***>
Hey jack i want to talk with you because i get stuck in nextjs13 i just need may be 5 minutes can you help
I sympathize, but please don't use GitHub comments for these types of requests. There is a Discord server associated with the channel, please use that to ask your question and please read and follow the #rules before posting.
No problem, I understand. sorry for that i will use discord i apologize for that
On Sun, Oct 15, 2023, 7:08 PM Jack Herrington @.***> wrote:
Hey jack i want to talk with you because i get stuck in nextjs13 i just need may be 5 minutes can you help
I sympathize, but please don't use GitHub comments for these types of requests. There is a Discord server associated with the channel, please use that to ask your question and please read and follow the #rules before posting.
— Reply to this email directly, view it on GitHub https://github.com/jherr/nextjs13-pokemon/issues/2#issuecomment-1763388964, or unsubscribe https://github.com/notifications/unsubscribe-auth/A6P7ZXQDCLROGLLKODCYZDLX7PPV3ANCNFSM6AAAAAAV45XLIE . You are receiving this because you commented.Message ID: @.***>
@jherr sorry to add to the fray but I checked out the link you posted and found your opinions on moving away from shared state on the server interesting. Assuming you might have a min at some point to asynchronously chat, do you have any other means of getting in touch other than Discord (or Twitter, not on there)? I haven't used it in awhile, but just tried to sign up to your channel... but it flagged me as a hacker ("something unusual is going on" Lol) and wouldn't let me in.
If not no biggie. Basically I'm a bit baffled about the push away from global state on the "server". I'm not understanding why the tide is pushing against it, especially now that Node supports request safe async context. Behind the scenes, Next's patched fetch uses a global variable on the server to cache fetch requests for example... so why shouldn't we?
If you add
console.log(store.getState())
to thepage.tsx
component before thestore.dispatch(setStartupPokemon(data))
and run the app, the first request will log emptystartupPokemon
array as expected but subsequent requests log already populated array. My educated guess is that because server components can't use context, and we access the Redux store directly, it's state is shared instead of being created for every new request.This is basically non-issue for trivial applications like this, but I can't imagine building anything more complex with this where user info could be leaked or something like that. Is there any solution to this or are server components just not made for more complex use cases?