Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Anti-pattern: reacting to @@INIT action #186

Closed
gaearon opened this issue Jun 28, 2015 · 18 comments
Closed

Anti-pattern: reacting to @@INIT action #186

gaearon opened this issue Jun 28, 2015 · 18 comments
Labels

Comments

@gaearon
Copy link
Contributor

@gaearon gaearon commented Jun 28, 2015

In the new docs (#140) we should clarify that any actions prefixed with @@ are not meant to be handled. For example, you should never try to handle @@INIT. We might enforce that by slightly randomizing names (e.g. @@INIT_2hj3jh34).

Handling @@INIT manually will break hot reloading. It is invoked at every hot reload, so if you do your initial data transformation there, it won't work the second time.

I've seen people using @@INIT to hydrate the plain objects received from the server into the Immutable state. Instead of handling @@INIT, you need to consider one of two options:

  • convert your whole plain object state to Immutable right away before passing it to Redux;
  • check if the state is a plain object and use fromJS before handling the action.
function myReducer(state = {}, action) {
  if (!isImmutable(state)) { // some kind of typeof check here?
    state = Immutable.fromJS(state);
  }

  ...
}

It is easy to abstract this away with a createImmutableReducer function like this:

export default function createImmutableReducer(initialState, handlers) {
  return (state = initialState, action) => {
    if (!isImmutable(state)) {
      // Hydrate server plain object state
      state = Immutable.fromJS(state);
    }

    const handler = handlers[action.type];
    if (handler) {
      state = handler(state, action);
    }

    if (!isImmutable(state)) {
      throw new Error('Reducers must return Immutable objects.');
    }

    return state;
  };
}

It can then be used for creating reducers from action constant -> handler map.

@gaearon gaearon added the docs label Jun 28, 2015
@Markus-ipse
Copy link

@Markus-ipse Markus-ipse commented Jul 1, 2015

@gaearon What is "@@"? I'm assuming it's ES6, perhaps related to symbols, but google doesn't like special characters so it ungoogleable :(

Loading

@dariocravero
Copy link
Contributor

@dariocravero dariocravero commented Jul 1, 2015

@hummlas it's random to tell it's an internal :) @ooflorent proposed it as far as I remember

Loading

@Markus-ipse
Copy link

@Markus-ipse Markus-ipse commented Jul 1, 2015

Ah, I see, like old-school underscore prefixes, e.g. var _privateValue = "Private";? :)

It seem to be used in official spec-stuff as well, like iterables

"In order to be iterable, an object must implement the @@iterator method, meaning that the object (or one of the objects up its prototype chain) must have a property with a Symbol.iterator key"

https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Iteration_protocols

This confuses me a bit as you're supposed to implement an @@iterator method, which, to me, seems to be at odds with @@ meaning "internal"?

Loading

@gaearon
Copy link
Contributor Author

@gaearon gaearon commented Jul 1, 2015

Feel free to suggest better prefix. I have no idea what to choose to discourage people from actually handling them, but keep it readable. Maybe prefix with an emoji..

Loading

@clearjs
Copy link
Contributor

@clearjs clearjs commented Jul 1, 2015

I'd use something like @@redux/INIT, or @@redux/__INIT to stress that it's private. This would be similar to, e.g. @@transducer/step in that there is a namespace at the top.

Loading

@gaearon
Copy link
Contributor Author

@gaearon gaearon commented Jul 1, 2015

Oh, I like the namespace thing!

Loading

@dariocravero
Copy link
Contributor

@dariocravero dariocravero commented Jul 1, 2015

REDUX:INIT?

Loading

@clearjs
Copy link
Contributor

@clearjs clearjs commented Jul 1, 2015

I like the @@ because of possible familiarity (it is already used for iterators and transducers in a similar manner). Capitalization is to look like an action constant. Underscores as a hint for internals. Making it look frightening as an additional hint :) It would also be extensible for possible non-privately namespaced constants.

But any naming scheme should be fine, provided that it is unlikely to clash with user's action constants.

Loading

@Markus-ipse
Copy link

@Markus-ipse Markus-ipse commented Jul 2, 2015

Could symbols be used for methods and variables that aren't supposed to be handled by the consumer?

But maybe that would break the hot reloading as well? But then if that's the case that could be solved by exposing a collection of symbols, that way the methods/variables wouldn't be accessible without retrieving there corresponding symbol first?

I might be speaking out of ignorance here though as I have no experience with hot reloading or symbols (yet), so I defer to your superior knowledge in this area :)

Btw, I must say that reading the issues for Redux is extremely educational and enjoyable, it's so cool being able to follow along in the creation of a new library, especially the back and fourth between @gaearon and @acdlite when brainstoring new ideas. Kudos! :)

Loading

@clearjs
Copy link
Contributor

@clearjs clearjs commented Jul 2, 2015

Symbols might be problematic for use from third-party libraries: they would be required to import redux, which may lead to more coupling.

Loading

@gaearon
Copy link
Contributor Author

@gaearon gaearon commented Jul 6, 2015

Could symbols be used for methods and variables that aren't supposed to be handled by the consumer?

That's what I wanted at first, but we decided against them because it feels silly to drag a Symbol polyfill (16% of the lib size) just for that.

Loading

@acdlite
Copy link
Collaborator

@acdlite acdlite commented Jul 6, 2015

Maybe we should namespace the init type, like the transducer protocol does?

export const INIT = '@@redux/init';

Loading

@acdlite
Copy link
Collaborator

@acdlite acdlite commented Jul 6, 2015

Oh haha that was already suggested. Well I like that idea :D

Loading

@gaearon
Copy link
Contributor Author

@gaearon gaearon commented Jul 13, 2015

Fixed by #186.

Loading

@aravantv
Copy link

@aravantv aravantv commented Mar 21, 2016

Just for info, I arrived here precisely because I was feeling it would be bad to react to this action, so I think the name makes it actually pretty clear it should not be used. If you really want to make it clear that it should not be used I think the best name would be "@@INIT_action_do_not_react_to_this_action_check_issue_186_instead" or something alike...

Loading

@ghost
Copy link

@ghost ghost commented Dec 9, 2016

So I am in a situation where I would like to call a saga on startup. Is there any better way then listening to @@INIT ?

Loading

@brigand
Copy link
Contributor

@brigand brigand commented Dec 9, 2016

@MoeSattler const store = createStore(...); store.dispatch(...)

Loading

@Xesenix

This comment has been hidden.

@reduxjs reduxjs locked as resolved and limited conversation to collaborators Apr 29, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
8 participants