Reputation: 67898
I have two different components that leverage the same AuthStore
, FacebookUser
and Quiz
.
The FacebookUser
component updates the AuthStore
by executing the login
action and that actions causes it to execute emitChange
. However, the onChange
handler for the Quiz
does not fire.
console.log("AuthStore::CREATED");
var AppDispatcher = require('../dispatcher/AppDispatcher');
var EventEmitter = require('events').EventEmitter;
var AuthConstants = require('../constants/AuthConstants');
var assign = require('object-assign');
var CHANGE_EVENT = 'change';
var _user = undefined;
var AuthStore = assign({}, EventEmitter.prototype, {
isLoggedIn: function() {
return _user !== undefined;
},
getUser: function() {
return _user;
},
emitChange: function() {
console.log('AuthStore::emitChange');
this.emit(CHANGE_EVENT);
},
addChangeListener: function(callback) {
console.log('AuthStore::addChangeListener', callback);
this.on(CHANGE_EVENT, callback);
},
removeChangeListener: function(callback) {
this.removeListener(CHANGE_EVENT, callback);
}
});
// Register callback to handle all updates
AuthStore.dispatchToken = AppDispatcher.register(function(action) {
console.log('AuthStore::action', action);
switch(action.actionType) {
case AuthConstants.AUTH_LOGIN:
_user = action.user;
AuthStore.emitChange();
break;
case AuthConstants.AUTH_LOGOUT:
_user = undefined;
AuthStore.emitChange();
break;
default:
// no op
}
});
module.exports = AuthStore;
var AuthActions = require('../../actions/AuthActions');
var AuthStore = require('../../stores/AuthStore');
function componentWillMount() {
AuthStore.addChangeListener(this.onChange);
}
function onChange() {
console.log('FacebookUser::onChange');
var user = AuthStore.getUser();
this.setState(user);
}
function populateUserProfile(userId) {
FB.api('/' + userId, {fields: 'email,name'}, function(response) {
console.log('FacebookUser::populateUserProfile', response);
AuthActions.login(response);
}.bind(this));
}
var AuthStore = require('../../stores/AuthStore');
var QuizStore = require('../../stores/QuizStore');
function componentWillMount() {
AuthStore.addChangeListener(this.onChange);
QuizStore.addChangeListener(this.onChange);
}
function onChange() {
console.log('Quiz::onChange');
var quiz = QuizStore.getQuiz();
if (!quiz.person.email) {
var user = AuthStore.getUser();
quiz.person.email = user.email;
}
this.setState(quiz);
}
var Dispatcher = require('flux').Dispatcher;
module.exports = new Dispatcher();
I thought that the stores were Singleton's, however, it appears that's not the case. I know I'm missing something stupid. Looking forward to the answer!
Below you can see that the FacebookUser::onChange
fires. I'm pretty sure the issue is that the AuthStore
is created for both components. That's pretty visible from the AuthStore::CREATED
log.
AuthStore::CREATED
QuizStore::create
AuthStore::addChangeListener onChange() {
console.log('Quiz::onChange');
var quiz = QuizStore.getQuiz();
if (!quiz.person.email) {
var user = AuthStore.getUser();
quiz.person.email = user.email;
}
th…
QuizStore::addChangeListener onChange() {
console.log('Quiz::onChange');
var quiz = QuizStore.getQuiz();
if (!quiz.person.email) {
var user = AuthStore.getUser();
quiz.person.email = user.email;
}
th…
AuthStore::CREATED
AuthStore::addChangeListener onChange() {
console.log('FacebookUser::onChange');
var user = AuthStore.getUser();
this.setState(user);
}
FacebookUser::statusChangeCallback Object {authResponse: Object, status: "connected"}
FacebookUser::populateUserProfile Object {email: "[email protected]", name: "Michael Perrenoud", id: "10209047315608853"}
AuthActions::login
AuthStore::action Object {actionType: "AUTH_LOGIN", user: Object}
AuthStore::emitChange
FacebookUser::onChange
Upvotes: 0
Views: 905
Reputation: 67898
So the issue ended up being a bit esoteric. I was including this user component with a different ReactDOM
renderer. Effectively like its own application. This is what was causing the problem. Because they were in different scopes they didn't share the same stores. Moving the component to being rendered by the root component for the application fixed it.
Upvotes: 0
Reputation: 9430
Rather than exposing the constructor expose an instance call new on your stores and expose that instance. That way it will be a singleton, in tests I expose a non default export so I can reinititialse a store for each test.
Upvotes: 0