cbdeveloper
cbdeveloper

Reputation: 31335

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

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.

Upvotes: 4

Views: 805

Answers (1)

Levon Ghazaryan
Levon Ghazaryan

Reputation: 109

Redux is designed for data centralisation and management such as loading some dynamic data changing it during the application lifetime and so on.Since you are not going to change that values because your application can’t run in both environments on a same time or switch between them that mean you don’t need to change them during application lifetime and if some variable should not change value it should be declared as a CONSTANT. So declare it as a constant and important whenever you need to access it.

Upvotes: 1

Related Questions