How to provide my <App/> with data that is built differently on client and server renders and is needed by the <App/> and its thunks?

Viewed 33

I have some data that is only defined in my index.tsx file, right before I render my <App/>. Once that data is defined, it does not change anymore. I need my <App/> to be aware of that data.

Other needs:

  • Sometimes that data is needed inside a component (i.e: would be accessible via context and state)
  • Sometimes that data is needed inside a redux thunk (i.e: would be accessible only via state, or parameter passed to the thunk)

For example:

index.tsx

const COUNTRY = getCountry(window.location);

ssrApp.tsx (on server)

const COUNTRY = getCountry(req.hostname);

My dilema is that I cannot export that data from the index.tsx or the ssrApp.tsx files, because they are 2 different files and one is for client and one is for server rendering. I also need to provide that data to my <App/>.

The easier route I guess would be to pass to the app via context. Like:

render(
  <SomeContext.Provider value={COUNTRY}>
    <App/>
  </SomeContext.Provider>
);

I started doing this, and it worked nicely for the most parts, but it broke when I started needing that data inside a thunk. AFAIK, thunks don't get ACCESS to the context. But they can access state (redux state).

So I created a redux state that I call PRELOADED, and I add that data to the store as a preloaded state value.

Something like:

configureStore({
    reducer: rootReducer,
    preloadedState: {
      PRELOADED: {
        COUNTRY: getCountry(window.location)
      }
    }
  });

It solves the "accessible to thunks" problem, but it creates other problems.

Because @reduxjs/toolkit demands you to initialize every state slice, even though you know for sure that that state will ALWAYS be preloaded.

const PRELOADED_SLICE = createSlice({
  name: "PRELOADED",
  initialState: getInitialState(),
  reducers: {
    SOME_ACTION(state, action: SOME_ACTION) {
      // DO SOMETHING
    }
  }
});

So you end up having to create a "dummy" initialState, because the real state will only be defined in run-time.

Anyway, the PRELOADED state approach seems to do the work so far. Is there a best practice to this problem?

1 Answers

This is static data, right, so why not include it in a source file and import it to both index.tsc and ssrApp.tsx if they both need it.

Alternatively using your PRELOADED slice, why not just populate the getInitialState() with the data you need in the first place and have no Actions and a noop reducer in that slice?

I have a feeling your description I have some data that is only defined in my index.tsx file, right before I render my <App/>. actually means something other than static data.

Related