DEV Community

Discussion on: Mobx Server Side Rendering with Next.js

 
ivandotv profile image
Ivan V. • Edited
  1. You can use mobx without providers or hooks, just import the store, and reference it directly in the component.
    The reason I'm using the provider component and useRootStore hook is because of the testability of the components. Without them, how are you going to substitute (mock) the store when testing the components with something like react-testing-library?
    Root store is used in _app component, everything that is included in the _app component must be bundled for "first page load". If you don't need your store present through the whole app, don't include it in the root store, and load it only on the pages where it is needed, that will decrease the size.
    Question: suggested best practice for holding onto a store constructed with props #74

  2. I believe that you are wrong here because useRootStore can never trigger a render, all it does is return a stable reference to the mobx store (always the same object). The same applies for the root provider component, it will never trigger a render, the only purpose of the provider component and the hook is to enable easier testing (maybe I should have mentioned that in the article). In your example, how are you going to test your component in isolation?

  3. In nextjs, the application always renders twice once on the server, and then on the client, it has nothing to do with Mobx. getServerSideProps and getStaticProps are essentially hydration for react components and the principle is the same. You need to decide if you want to render an "empty" store in the browser when the page loads.
    If care about SEO, then you will render on the server, so the crawler has something to index.

All good questions, keep'em coming :)

Thread Thread
 
greggcbs profile image
GreggHume

1 . That is a good idea but then at some point its not clear what is available in the root context and what is not. But thats development.

2 . I am not doing testing so i didnt think of that, good point. To clarify this unnecesarry rerender discussion, I see you have done storeContext different to another example I was looking at and I got the two mixed up. To clarify your code anyways, does useContext know that you are passing an existing context in?

How much execution happens when this is run:

export function useRootStore() {
  const context = useContext(StoreContext);
  if (context === undefined) {
    throw new Error("useRootStore must be used within RootStoreProvider");
  }

  return context;
}
Enter fullscreen mode Exit fullscreen mode

^ because from what I have seen, this function will run everytime a change happens in a component, if the component is wrapped with mobx observable. And if useContext does some processing when it is invoked then i am worried about this extra processing.

3 . I was not saying mobx causes both renders, i was saying that they happen anyways. Hydration happens anyways.

So if I do this, it has the same effect as what you were doing:

export async function getStaticProps(res) {
    return {
        props: {
            company: data[0].data,
            listingsByCategory: data[1].data.categories
        },
        revalidate: 300,
    }
}

export default function Company({company, listingsByCategory}) {
    companyStore.hydrate({company});
    listingStore.hydrate({listingsByCategory});

    return (
        <>
            <SomeComponentsThatUseTheStoreInternally />
        </>
    );
}
Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
ivandotv profile image
Ivan V. • Edited
  1. useRootStore hook is just a way to get to the root store without explicitly declaring the store inside the component, it's just getting back the value that is stored in context, and if there is no context above, it throws.

3.Yes exactly :) You just need to guard against calling the hydration more than once, currently if will hydrate every time the Company component is rendered.