How can I keep state that will not change inside Redux store?

Viewed 381

I'm building a Single App that will do SSR (server side rendering) and I'm using React + Redux.

I've just started to implement Redux in this app. It was previously built app using only React's useState, useContext etc.

The fact is that sometimes I need my app code to be aware of the environment that it's running, either ON_CLIENT or ON_SERVER, to skip some window.something statement, for example.

Before Redux, I was doing the following:

index.js (this could be the index.js of my client bundle or my server bundle)

ReactDOM.render(
  <App
    ON_SERVER={false}               // THIS IS TRUE ON SERVER CODE
    ON_CLIENT={true}                // THIS IS TRUE ON CLIENT CODE
    ... other stuff
  />
,document.getElementById('root')
);

App.js

...
const environment = {
  ON_SERVER: props.ON_SERVER,
  ON_CLIENT: props.ON_CLIENT
}

...

// PROVIDING IT USING REACT CONTEXT

return (
  <EnvironmentContext.Provider value={environment}>
    <MyComponents/>
  </EnvironmentContext.Provider>
);

And then, inside some component, I can do this pattern:

SomeComponent.js

const {ON_CLIENT} = useContext(EnvironmentContext);
ON_CLIENT && window.something;

And I want to improve this pattern with Redux.

I want to keep this in the Redux store, so I can get rid of the EnvironmentContext and access it with:

const {ON_CLIENT} = useSelector((state) => state.environment);

So I've thought of doing:

index.js

const store = createStore(rootReducer, {
  environment: {
    ON_CLIENT: true,               // THIS IS TRUE ON CLIENT CODE
    ON_SERVER: false               // THIS IS TRUE ON SERVER CODE
  }
});

But since I don't have a corresponding reducer for this piece of state (environment), I got this error msg:

redux.js:319 Unexpected key "environment" found in preloadedState argument passed to createStore. Expected to find one of the known reducer keys instead: "auth", "appVersion", "siteData". Unexpected keys will be ignored.

NOTE: auth, appVersion and siteData are pieces of state which I have corresponding reducers for.

Here is my rootReducer:

const rootReducer = combineReducers({
  auth: updateAuth,
  appVersion: updateClientVersion,
  siteData: updateSiteData
});

QUESTION

Can I have some piece of state that will not change, and therefore is not handled by any reducer? Or in this case I do need to set up some dummy reducer just to always return that same state? PS: It does the trick, but it feels wrong, though.

// NOTE: I will always preload this state, in the `createStore` call, so the state will never be undefined.

function returnEnvironment(state={}, action) {
  return state;
}

const rootReducer = combineReducers({
  auth: updateAuth,
  appVersion: updateClientVersion,
  siteData: updateSiteData,
  environment: returnEnvironment
});

Does anybody have a better alternative to this?

I've looked at this discussion: https://github.com/reduxjs/redux/issues/1457

There are some suggestions to populate the global object, but I'd rather keep it all inside React and Redux.

PS: Sorry for the long question, but I wanted to make my use case as clear as I could, so somebody might have a better pattern.

0 Answers
Related