Redux & firebase.auth().onAuthStateChanged

2,004 views
Skip to first unread message

Brandon Paquette

unread,
Jun 5, 2016, 10:03:46 PM6/5/16
to Firebase Google Group
Wondering if anyone else has encountered this problem w/ the payload from onAuthStateChanged() in Redux.

This is my reducer that listens for changes in auth:

[USER_LOGGED_IN_A]: (state, action) => Object.assign({}, state, action.userPayload);
[USER_LOGGED_IN_B]: (state) => state;
[USER_LOGGED_IN_C]: (state, action) => Object.assign({}, state, action.userPayload);

This is my action creator that starts the auth listener & dispatches the user data payload upon login

export const startAuthListener = function () {

 
//this listener will update state upon changes of auth status.

 
return (dispatch, getState)=> {   //using a redux-thunk instead of normal action

   firebase
.auth().onAuthStateChanged(function (user) {
     
     
if (user) {
         
// User is signed in, dispatch action
         console
.log(user);

         
//action A
         dispatch
({type: USER_LOGGED_IN_A, userPayload: user.providerData})

         
//action B
         dispatch
({type: USER_LOGGED_IN_B})

         
//action C
         dispatch
({type: USER_LOGGED_IN_C, userPayload: user})
     
}
 
});
 
}
}



The console.log statement works fine--the {user} object is returned and appears in order.
Actions A and B also fire, and the state updates appropriately.

Now here's where it gets weird. Action C never fires--no errors, no state
updates, no record of the action emitting (as per Redux DevTools).
The only sign of life I can detect is if I put a console.log statement in the reducer function.  
That works fine & the object appears normal. 

I've been troubleshooting this for some time & can't arrive at a good explanation.
Redux appears to be working fine w/ every object I throw at it, so I'm guessing it's something to do
with the auth data object.

I'm using the latest client SDK, loaded in my index.html file from https://www.gstatic.com/firebasejs/live/3.0/firebase.js

Anyone encounter this before?






Jacob Wenger

unread,
Jun 6, 2016, 3:08:41 AM6/6/16
to fireba...@googlegroups.com
Have you tried emitting action C with a different object to make sure that the user object itself is causing the issues? It's possible it contains something which is tripping up Redux, but that seems more like a Redux bug than a Firebase bug. I would try to eliminate top-level keys off of the user object and see if you can track down which one is causing the action to not fire. I'm not sure I'll be able to be of much help without a repro on JSFiddle or Plunkr. I'm interested to hear what you find though, so please do share the results.

Cheers,
Jacob

--
You received this message because you are subscribed to the Google Groups "Firebase Google Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to firebase-tal...@googlegroups.com.
To post to this group, send email to fireba...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/firebase-talk/c35d12ac-9f5b-4b60-aeda-ffe15d871174%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Brandon Paquette

unread,
Jun 6, 2016, 11:02:15 AM6/6/16
to fireba...@googlegroups.com

So action A, the user.providerData, is itself another object, and fires just fine. So too does any other object I've tried (including across several redux projects), which is one of the reasons I started thinking it might be a Firebase thing (new SDK and all). This setup also worked fine in the previous firebase SDK.

Good idea re: trying one property at a time. If that doesn't find the problem, I'll try and setup a minimal example. Thanks Jacob.

--
You received this message because you are subscribed to a topic in the Google Groups "Firebase Google Group" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/firebase-talk/Lp6I9uS0PAo/unsubscribe.
To unsubscribe from this group and all its topics, send an email to firebase-tal...@googlegroups.com.

To post to this group, send email to fireba...@googlegroups.com.

Ben Mueller

unread,
Jun 6, 2016, 12:00:58 PM6/6/16
to Firebase Google Group
Potentially dumb idea: you have "if (user)" in your code. Why not throw a console.log("user", user) right above that if statement, and see what comes back from the case that's breaking.

Douglas Correa

unread,
Jun 6, 2016, 1:32:10 PM6/6/16
to fireba...@googlegroups.com
Hi Bradon,

I had the same issue trying to dispatch an action putting in the payload the entire user Object from onAuthStateChanged, and I found that the user Object is "too big" and there are a lot of properties and method we don't need to store in the Redux state.

So I made a transform function to filter the properties I want to store: https://gist.github.com/douglascorrea/003ae6a6b11f19c97d6ee5b28d0d9eef

So you dispatch your action using something like this: dispatch(userLoggedInSuccess(transformFirebaseUser(user)));

I'm working in a React Readux Firebase Starter that you can look at https://github.com/douglascorrea/react-hot-redux-firebase-starter

This is still a work in progress, you can watch that repo to check when it will be completed.

Douglas


Ben Mueller

unread,
Jun 6, 2016, 1:38:14 PM6/6/16
to fireba...@googlegroups.com
Yeah, actually that makes a lot of sense, regardless of whether it resolves OP's issues or not

Jacob Wenger

unread,
Jun 6, 2016, 1:52:49 PM6/6/16
to fireba...@googlegroups.com
@Douglas - Ahh interesting! I didn't know Redux had a limit to the size of action dispatch payloads. Is this documented somewhere? Do you by chance know what the limit is? It is definitely best practice to only store the state you actually need in your Redux store so transforming it like you did seems like a great solution. Thanks for the advice!

Ben Mueller

unread,
Jun 6, 2016, 2:06:22 PM6/6/16
to fireba...@googlegroups.com
Hmm…I don’t know if Redux has limits. It’s just stored in memory, so I think that’s governed only by how much memory the OS gives to the browser. Of course, if you’re trying to store your Redux store in a cookie or session storage (which is what I’m doing, to help with persistence if a user reloads their browser), then you’ll hit storage limits relatively fast.

Redux can only store simple JS objects, though, so maybe if there’s a bunch of other cruft returned from Firebase, like functions and the like, Redux may choke on those. But that’s just speculation on my part. Doug’s suggestion of just storing the stuff you really need (auth token, email, name, etc) is a good idea regardless of whether it solves your problem, and may manage to solve your problem along the way.


Douglas Correa

unread,
Jun 6, 2016, 2:16:45 PM6/6/16
to fireba...@googlegroups.com
@Jacob,

I don't know if is a size limitation, or the error happens because of user object contents, but transforming it before dispatch the action solved the problem and makes more sense.

I also was having the "Uncaught SecurityError: Blocked a frame with origin" when trying to dispatch the whole object, probably because some Redux/Firebase internal handling exception. And it also stopped when I stop trying to dispatch the entire object. And it seems that it is an know issue as we can see here too (http://stackoverflow.com/questions/37402109/firebase-3-0-throws-cross-origin-error-when-bundled-with-webpack)

Douglas Correa

Jacob Wenger

unread,
Jun 6, 2016, 2:36:08 PM6/6/16
to fireba...@googlegroups.com
Yeah, now that I think about it, I can't imagine size is the problem since the response isn't that big. I'm not surprised to hear that it may contain some things in the object which Redux doesn't handle though. Pretty annoying I'm sure. I have a feeling an error must be silently eaten somewhere along the line in Redux or developer code. I don't have a ton of time to dig into this specific issue at the moment, but if you have any other information, can track down the faulty key / value in the object, or can share a minimal repro in JSFiddle or Plunkr, I would greatly appreciate it. We may even be able to change the response payload on our side depending on what exactly is causing the issue and whether or not it will be a breaking change for us.

Brandon Paquette

unread,
Jun 6, 2016, 3:02:13 PM6/6/16
to fireba...@googlegroups.com
thanks for cogitating on this problem all. have some updates. i tried to keep up w/ conversation but was testing this bug, so hopefully didn't miss anyone's ideas.

re: 'only store what you need in state' - agreed, and this is the route i took ultimately--i.e., parsing out props of interest in the action creator before dispatch().  i've been parsing objects in my reducers, though, which i don't think is an anti-pattern--so this bug was irksome 

re: redux size limits. afaik there are no size limits, and i'm certain i've held larger objects in state. but as noted, sizes of these objects are trivial so this hopefully isn't the issue

re: methods vs. properties. tested by identifying functions using lodash isFunction and dispatching them alone:  no issues. 


update: using these ideas I ran some more tests. i've concluded that there are 4 specific members of the auth response object that Redux can't handle.  their keys are:  ["O", "yd", "lc", "o"]

i tried dispatching each individual property by itself, and these 4 caused the script to hang (no visible errors, but code after the dispatch never fired, and Redux DevTools didn't register the action). 

What do these properties have in common?

i'll try and set up a repo if these revelations don't point to an obvious answer.

thanks all
brandon

Ben Mueller

unread,
Jun 6, 2016, 3:05:01 PM6/6/16
to fireba...@googlegroups.com
I’m 99.9% sure that those are internal Firebase functions, and not anything that is intended to be consumed outside of Firebase. I see function names like that in the console if and when I run into a Firebase error. So yeah, if you’re trying to put those into Redux, I can certainly see where that would have deleterious effects.


Brandon Paquette

unread,
Jun 6, 2016, 3:36:07 PM6/6/16
to fireba...@googlegroups.com
so strange. wonder if it's a limitation of Redux or some way in which the firebase SDK fiddles w/ the object once its created.

here's a repo w/ the issue @ hand. lmk if there are any problems getting it up-and-running. 



Jacob Wenger

unread,
Jun 16, 2016, 1:48:34 PM6/16/16
to fireba...@googlegroups.com
@Brandon - I am not able to get the setup instructions on your repo to work. I tried several different versions of Node. Can you double check that they work from a fresh install? Can you also please let me know which version of Node.js I should use? Here is the error I am getting when running npm start:

$ npm start

> react-redux...@3.0.0-alpha.0 start /Users/jwenger/Desktop/firebase_redux_bug
> better-npm-run start

running better-npm-run in /Users/jwenger/Desktop/firebase_redux_bug
Executing script: start

to be executed: babel-node bin/server 
/Users/jwenger/Desktop/firebase_redux_bug/bin/server.js:1
(function (exports, require, module, __filename, __dirname) { import config fr
                                                              ^^^^^^
SyntaxError: Unexpected reserved word
    at exports.runInThisContext (vm.js:73:16)
    at Module._compile (module.js:443:25)
    at loader (/Users/jwenger/Desktop/firebase_redux_bug/node_modules/babel-register/lib/node.js:158:5)
    at Object.require.extensions.(anonymous function) [as .js] (/Users/jwenger/Desktop/firebase_redux_bug/node_modules/babel-register/lib/node.js:168:7)
    at Module.load (module.js:355:32)
    at Function.Module._load (module.js:310:12)
    at Function.Module.runMain (module.js:501:10)
    at /Users/jwenger/Desktop/firebase_redux_bug/node_modules/babel-cli/lib/_babel-node.js:160:24
    at Object.<anonymous> (/Users/jwenger/Desktop/firebase_redux_bug/node_modules/babel-cli/lib/_babel-node.js:161:7)
    at Module._compile (module.js:460:26)

I'm gonna try to spin up my own minimal repro and see if I can figure anything out. I'll report back here if I discover anything.

Jacob

Jacob Wenger

unread,
Jun 16, 2016, 2:36:35 PM6/16/16
to Jacob Wenger, fireba...@googlegroups.com
Okay, I was able to reproduce this issue by slightly modifying Douglas' react-hot-redux-starter-firebase (nice job on that BTW!). I got the same error Douglas mentioned:

Blocked a frame with origin "http://localhost:3000" from accessing a cross-origin frame.

From doing some random deleting of attributes, I discovered that if I removed s, things would consistently work. It turns out then when I tried to JSON.stringify() that object, I got the following error:

Converting circular structure to JSON

So, that is probably the underlying issue. We have a circular reference in there somewhere and that is tripping up Redux. This is probably "works as intended" from Redux's perspective and we should update our payload to remove this circular reference (which should be avoided in general). I will follow up with our auth team and see what we can do here.

I would definitely suggest you use something like Douglas' extractUserProperties() method to filter the payload we return. In general, you will want your actions to send only the bare minimum information you need.

Cheers,
Jacob

Thomas Césaré-herriau

unread,
Jun 16, 2016, 9:05:34 PM6/16/16
to Firebase Google Group, ja...@firebase.com
Hey everyone,

Thanks for looking into this!

We think there's two things happening here.

The first thing is that the dispatch method of Redux is not supposed to take anything else than a plain Object (https://github.com/reactjs/redux/blob/master/src/createStore.js#L149). The method it uses to test if the action passed is a plain object (lodash.isPlainObject) tests if the object given is a plain object but not if its properties are, and sub-properties... The issue is that Redux probably uses JSON.stringify internally, and the requirement of this function is stronger than just a plain object. It has to be a "recursively" plain object - if that makes sense. In your case Brandon, you do pass a "plain object" if we only consider the top level, so Redux doesn't raise any error, but ends up failing silently at some point. I would say that's a bug in Redux not to ensure the object is fully stringifi-able when it's actually the requirement.

That being said, it is true you can't stringify the user payload, and this is the second issue. We will work on a fix to solve this. I have to mention though that by stringifying and parsing this object, you will lose all its functionality as it's not a plain object.

Let me know if that makes sense!

Douglas Correa

unread,
Jun 20, 2016, 10:27:21 AM6/20/16
to fireba...@googlegroups.com
Hi,

I think makes sense to fix the user payload to be "stringifable", but I also think that we should put as minimum data into our application as it requires, in other words, we probably don't need all user payload to be stored into Redux state. That is why I made the function mentioned by Jacob here.

One thing I see as improvement to work with Redux as get back the sync method to get Auth state. That worked in 2.x but it was removed from 3.x. That is why I need to use OnAuthChange and unsubscribe it. But I think this will messy this thread so let's discuss it in another thread!

Douglas 

Reply all
Reply to author
Forward
0 new messages