jherr / nextjs13-pokemon

A Redux/NextJS 13 example using the App directory
79 stars 39 forks source link

Any particular reason for an intermediary component to pass data to the client? #1

Open unleashit opened 1 year ago

unleashit commented 1 year ago

Great videos Blue Collar Coder! But since Providers is itself a RCC why not just send the data directly to it and initialize the client store from there? I haven't used Redux lately, but I've had the basic idea working with plain React Context and useReducer. Basic example:

export default async function Home() {
  const req = await fetch("http://localhost:3000/api/search");
  const data = await req.json();
  store.dispatch(setStartupPokemon(data));

  return (
    <main>
      <Providers data={data}>
        <SearchInput />
      </Providers>
    </main>
  );
}

Then something like this (where initStore returns the store with the now hydrated data as initial state):

function Providers({ data, children }: { data: Pokemon[], children: React.ReactNode }) {
  return (
    <Provider store={initStore(data)}>
        {children}
    </Provider>
  );
}
jherr commented 1 year ago

That would definitely work as well. Thanks for that!

unleashit commented 1 year ago

You bet. I'm as confused as anyone about the RSCs so confidence level around best practices isn't exactly high yet! I've learned a few tricks from you and appreciate it.

p.s. if you have a sec check out https://github.com/unleashit/fetch-cache and see if you think the idea is useful. Main thing it does over the default fetch is that it also works on the client (albeit not as fancy as React Query) and lets you log what's going on.

jherr commented 1 year ago

They keep us content folks busy with new stuff, that's for sure.

Looked at fetch-cache. What would be good is an examples directory that showed how to use this across both server and client.

unleashit commented 1 year ago

Don't want to go off topic too much, but thanks for taking a look and good suggestion. I'm not sure if it's worth investing much more time, but depending how it evolves on my projects (and I'm still using it), I certainly will do that. There's really not much currently different between client and server though, other than how you probably want to initialize it on the server (in React.cache if using Next 13 to avoid leaking between requests). Also caching on the server is always on per request lifecycle.

It's not trying to be a state manager. Basically I like the idea colocating data fetching in components but wanted more control than Next's patched fetch. This can access or see what's in cache, invalidate by key... plus comes part of the way towards being a combination of axios (double promise handling) and React Query (but without all the features lol).

GLD5000 commented 1 year ago

@jherr great tutorial as always!

@unleashit Nice Idea! Something like this?

"use client";

import { Provider } from "react-redux";
import { store } from "@/store";
import { InitialData } from "@/types";
import { useRef } from "react";
import { setInitialData } from "@/store/searchSlice";

function Providers({
  initialData,
  children,
}: {
  initialData: InitialData[];
  children: React.ReactNode;
}) {
  const loaded = useRef(false);
  if (!loaded.current) {
    store.dispatch(setInitialData(initialData));
    loaded.current = true;
  }

  return <Provider store={store}>{children}</Provider>;
}

export default Providers;
unleashit commented 1 year ago

Looks good to me I think, although I haven't been working with the app directory lately and am a bit out of the loop. I can't remember if Jack's solution covers it, but one piece of the puzzle was how to create/persist the store for use in server components, and only during the lifetime of the request. I ended up setting up a module that conditionally exported a React.cache() wrapped store or a normal version depending on typeof window. Then you can have access the store in server components, where context isn't allowed.

GLD5000 commented 1 year ago

Great- thank you for taking a look! I also can't remember anything about persistence or state lifetimes in there- I shall have to delve deeper into the topic at some point!