Reputation: 13507
Here is the average Store:
// StoreUser
import EventEmitter from 'eventemitter3';
import Dispatcher from '../dispatcher/dispatcher';
import Constants from '../constants/constants';
import React from 'react/addons';
import serverAddress from '../utils/serverAddress';
import socket from './socket';
var CHANGE_EVENT = "change";
var storedData = {
userName: null
}
socket
.on('newUserName', (newUserName)=>{
storedData.userName = newUserName;
AppStore.emitChange();
})
function _changeUserName (newUserName) {
socket.emit('signUp', newUserName)
}
var AppStore = React.addons.update(EventEmitter.prototype, {$merge: {
emitChange(){
// console.log('emitChange')
this.emit(CHANGE_EVENT);
},
addChangeListener(callback){
this.on(CHANGE_EVENT, callback)
},
removeChangeListener(callback){
this.removeListener(CHANGE_EVENT, callback)
},
getStoredData(callback) {
callback(storedData);
},
dispatcherIndex:Dispatcher.register(function(payload){
var action = payload.action;
switch(action.actionType){
case Constants.CHANGE_USER_NAME:
_changeUserName(payload.action.actionArgument);
break;
}
return true;
})
}});
export default AppStore;
Here is average component, connected to the store:
import React from 'react';
import StoreUser from '../../stores/StoreUser';
import Actions from '../../actions/Actions';
export default class User extends React.Component {
constructor(props) {
super(props);
this.state = {
userName: null,
};
}
componentDidMount() {
StoreUser.addChangeListener(this._onChange.bind(this));
}
componentWillUnmount() {
StoreUser.removeChangeListener();
}
render() {
const { userName } = this.state;
return (
<div key={userName}>
{userName}
</div>
);
}
_onChange(){
StoreUser.getStoredData(_callbackFunction.bind(this))
function _callbackFunction (storedData) {
// console.log('storedData', storedData)
this.setState({
userName: storedData.userName,
})
}
}
}
This was working absolutely fine. But now, I'm facing quite big mistake in this approach:
WebApp has, say, sidebar with user's name, which is listening to StoreUser in order to display up to date userName. And also, the webapp has a component (page), which contains user's profile (including userName), which is also listening to StoreUser. If I will unmount this component, then the sidebar will stop listening to StoreUser too.
I've learned this approach from egghead.io or some other tutorial - I don't remember, where exactly. Seems, I've missed some important point about how to manage store listeners. Could you, please, suggest simple approach to solve the described issue?
I'm trying to stick to the original Flux architecture, please, don't advice me any alternative implementations of Flux architecture. This is the only issue I have.
Upvotes: 0
Views: 127
Reputation: 4002
The issue is that you aren't removing the your listener when you unmount. You have to be very careful to remove exactly the same function reference that you added (passing this.callback.bind(this)
twice doesn't work, since the two calls return different function references). The simplest approach would be:
//...
export default class User extends React.Component {
constructor(props) {
super(props);
this.state = {
userName: null,
};
// create fixed bound function reference we can add and remove
// (like the auto-binding React.createComponent does for you).
this._onChange = this._onChange.bind(this);
}
componentDidMount() {
StoreUser.addChangeListener(this._onChange);
}
componentWillUnmount() {
// make sure you remove your listener!
StoreUser.removeChangeListener(this._onChange);
}
//...
There are a couple of oddities with your code:
Upvotes: 1