redux-ui icon indicating copy to clipboard operation
redux-ui copied to clipboard

Does not work with server-side rendering because of Immutable

Open sompylasar opened this issue 9 years ago • 20 comments

After the state gets serialized into plain JavaScript objects on the server-side, and deserialized on the client-side, the action-reducer gets a non-default state of type Object, not Immutable Map it expects.

const defaultState = new Map({
    // ...
});

export default function reducer(state = defaultState, action) {
    // `state` is of type `Object` on state rehydration from the serialized data.

So, this line fails with an exception about missing get function: https://github.com/tonyhb/redux-ui/blob/master/src/action-reducer.js#L96

const customReducers = state.get('__reducers');

You use Immutable objects in actions, too. This can fail if these actions get serialized and replayed later (one of the core features of Redux is replayability, mainly for testing and debugging purposes). https://github.com/tonyhb/redux-ui/blob/master/src/action-reducer.js#L138 https://github.com/tonyhb/redux-ui/blob/master/src/action-reducer.js#L165

Having a non-serializable (non-POJO) state and actions leads to such incompatible behavior. Please either drop Immutable entirely -- it really appears to be unnecessary -- or make the state and actions serializable by converting Immutable objects to POJO via .toJs().

sompylasar avatar Dec 20 '15 00:12 sompylasar

Christmas and new years happened, apologies for the delay. Getting around to this little runt between now and Wednesday.

tonyhb avatar Jan 04 '16 14:01 tonyhb

Been thinking about this over the past few days. I don't want to use immutable because I feel as if Immutable should always be used in reducers. It helps us:

  • Strictly compare state for optimization, if desired
  • Deeply set, get and merge properties within a tree

We do server-side rendering at Docker and I'd expect that if you're casting .toJS() on the store as you deflate the state you should also inflate the state using .fromJS during your setState() call — that's how we're handling this.

I'll see if we can make an inflate() method ourselves that recurses down the UI state tree converting each component's state to an object. That's a potential plan.

I agree that Immutable within an action is incorrect; I'll change that in an upcoming PR.

tonyhb avatar Jan 07 '16 16:01 tonyhb

Have you looked at freeze-during-development middleware, and thought of not using Immutable at all for most of the cases? If, for some action, you need a deep manipulation on the state in the reducer, you could wrap the current state into an Immutable via fromJS, do the mutations, then convert the new state object back to POJO via toJS and return it.

I'm sure redux-ui should not impose using Immutable.

sompylasar avatar Jan 08 '16 12:01 sompylasar

Deeply getting/setting and strict comparison are two big perks of Immutable. I don't see why it's such a dealbreaker.

tonyhb avatar Jan 11 '16 01:01 tonyhb

@tonyhb Because it's not serializable without calling any methods, AFAIK.

sompylasar avatar Jan 11 '16 03:01 sompylasar

Working on this issue at the moment too, going to try @tonyhb first suggestion.

thomasdavis avatar Feb 08 '16 00:02 thomasdavis

I am doing this

initialData.ui = Immutable.fromJS(initialData.ui);
let store = createStore(reducer, initialData);

And get the same error, tried a few other variations, not quite sure what to do. =D

Edit: Ignore this, the above works.

Seems like you could just auto detect this pretty easy? Or throw a warning "It looks like you are trying to pass a PJO to the reducer, please lock it and try again."

thomasdavis avatar Feb 08 '16 02:02 thomasdavis

@thomasdavis your solution does not work for me. The problem AFAIK is that is still returns a TypeError on the following line. Because in my initialState there is obviously no '__reducer' key, and so customReducers is undefiend https://github.com/tonyhb/redux-ui/blob/master/src/action-reducer.js#L98

@tonyhb how can i have a initialUIState without having a '__reducer' field in it? Maybe as a soluttion a notSetValue on the get function.

const customReducers = state.get('__reducers', new Map());

namjul avatar Feb 17 '16 11:02 namjul

i would really love to see immutable been removed from this module. the mutations are not that hard to do without depending on immutable that is over 56kb minified. So if i use this module in my project not depending on immutablejs it will add me 56kb for 'nothing'.

If mutation gets to complex one could still use http://facebook.github.io/react/docs/update.html for this cases.

But sure for projects already using immutable it's ok.

jamuhl avatar Mar 23 '16 15:03 jamuhl

I hear you and will look at removing immutable from the project for 1.0

tonyhb avatar Mar 30 '16 04:03 tonyhb

For us Immutable.js with the 56KB is a deal breaker for using this library. Would love to see it removed and this library being much lighter with dependencies

pgilad avatar May 05 '16 07:05 pgilad

Thanks for the heads up. Seems to be a fairly common request so we'll take a look and maybe have two reducers you can import; one for immutable and one for objects (potentially using lodash for _.set and _.get methods)

tonyhb avatar May 10 '16 18:05 tonyhb

Hi, any progress on removing the immutable lib?

martinkadlec0 avatar Jun 07 '16 08:06 martinkadlec0

@tonyhb anything we can do to help out? I really like the API this provides over https://github.com/threepointone/redux-react-local, but I'm restricted at work and can't really use ImmutableJS.

iamricard avatar Jul 14 '16 14:07 iamricard

For anyone interested, I have tried to make it work without ImmutableJS and I haven't encountered any issues (yet). You can use that fork until it's here.

iamricard avatar Jul 15 '16 09:07 iamricard

For anyone interested an alternative solution without any dependencies on immutableJS is https://github.com/gcazaciuc/redux-fractal

gcazaciuc avatar Aug 30 '16 12:08 gcazaciuc

Any news about it? The repo is still active? Last commit is in May

totty90 avatar Sep 03 '16 13:09 totty90

Wish I stumbled upon this sooner. I'm using https://github.com/tonyhb/tectonic and was really liking that module. Without redux-ui, I still would have to carry some of the actions/reducers to update the component. This muddies the water. Shame this repo has fallen into disrepair.

At least hand this over to OSS community so that it can be kept up-to-date.

mrchief avatar Aug 31 '17 14:08 mrchief

Correction: Looks like the author is still active, just not paying attention to this issue anymore. ANy specific reason @tonyhb for this neglect? Especially when @rcsole seems to have a PR ready that'll fix this?

mrchief avatar Aug 31 '17 14:08 mrchief

Figured out a workaround. In addition to "immutable-ising" ui, one needs to do the same for tectonic (if using tectonic)

initialState.ui = Immutable.fromJS(initialState.ui)
initialState.tectonic = Immutable.fromJS(initialState.tectonic)

Works for now. HMR is broken as mentioned in #21 so will have to wait for the 1.0 package. :(

mrchief avatar Sep 01 '17 14:09 mrchief