Fix wrong height calculation of react-list

react-list doesn't know the size of an item that just got rendered
(it only later caches this size), therefore it can't
correctly calculate the height of the list.
This commit is contained in:
Jannis Mattheis 2018-04-14 16:30:09 +02:00 committed by Jannis Mattheis
parent 881e66ea29
commit 74d7c7cc9e
3 changed files with 76 additions and 11 deletions

View File

@ -0,0 +1,40 @@
import ReactList from 'react-list';
// See also https://github.com/coderiety/react-list/blob/master/react-list.es6
class FixedReactList extends ReactList {
// deleting a messages or adding a message (per shift) requires invalidating the cache, react-list sucks as it does
// not provide such functionality, therefore we need to hack it inside there :(
ignoreNextCacheUpdate = false;
cacheSizes() {
if (this.ignoreNextCacheUpdate) {
this.ignoreNextCacheUpdate = false;
return;
}
super.cacheSizes();
}
clearCacheFromIndex(startIndex) {
this.ignoreNextCacheUpdate = true;
if (startIndex === 0) {
this.cache = {};
} else {
Object.keys(this.cache).filter((index) => index >= startIndex).forEach((index) => {
delete this.cache[index];
});
}
};
componentDidUpdate() {
const hasCacheForLastRenderedItem = Object.keys(this.cache).length && this.cache[this.getVisibleRange()[1]];
super.componentDidUpdate();
if (!hasCacheForLastRenderedItem) {
// when there is no cache for the last rendered item, then its a new item, react-list doesn't know it size
// and cant correctly calculate the height of the list, we force a rerender where react-list knows the size.
this.forceUpdate();
}
}
}
export default FixedReactList;

View File

@ -6,7 +6,7 @@ import MessageStore from '../stores/MessageStore';
import AppStore from '../stores/AppStore';
import * as MessageAction from '../actions/MessageAction';
import DefaultPage from '../component/DefaultPage';
import ReactList from 'react-list';
import ReactList from '../component/FixedReactList';
import {CircularProgress} from 'material-ui/Progress';
class Messages extends Component {
@ -29,6 +29,12 @@ class Messages extends Component {
updateAllWithProps = (props) => {
const appId = Messages.appId(props);
const reset = MessageStore.shouldReset(appId);
if (reset !== false && this.list) {
this.list.clearCacheFromIndex(reset);
}
this.setState({...MessageStore.get(appId), appId, name: AppStore.getName(appId)});
if (!MessageStore.exists(appId)) {
MessageStore.loadNext(appId);

View File

@ -7,10 +7,21 @@ class MessageStore extends EventEmitter {
constructor() {
super();
this.appToMessages = {};
this.reset = false;
this.resetOnAll = false;
this.loading = false;
AppStore.on('change', this.updateApps);
}
shouldReset(appId) {
let reset = appId === -1 ? this.resetOnAll : this.reset;
if (reset !== false) {
this.reset = false;
this.resetOnAll = false;
}
return reset;
}
loadNext(id) {
if (this.loading || !this.get(id).hasMore) {
return;
@ -32,8 +43,8 @@ class MessageStore extends EventEmitter {
}
handle(data) {
const {payload} = data;
if (data.type === 'UPDATE_MESSAGES') {
const payload = data.payload;
if (this.exists(payload.id)) {
payload.messages = this.get(payload.id).messages.concat(payload.messages);
}
@ -42,34 +53,42 @@ class MessageStore extends EventEmitter {
this.loading = false;
this.emit('change');
} else if (data.type === 'ONE_MESSAGE') {
const {payload} = data;
this.createIfNotExist(payload.appid);
this.createIfNotExist(-1);
this.appToMessages[payload.appid].messages.unshift(payload);
this.appToMessages[-1].messages.unshift(payload);
this.reset = 0;
this.resetOnAll = 0;
this.updateApps();
this.emit('change');
} else if (data.type === 'DELETE_MESSAGE') {
Object.keys(this.appToMessages).forEach((key) => {
const appMessages = this.appToMessages[key];
const index = appMessages.messages.indexOf(data.payload);
if (index !== -1) {
appMessages.messages.splice(index, 1);
}
});
this.resetOnAll = this.removeFromList(this.appToMessages[-1], payload);
this.reset = this.removeFromList(this.appToMessages[payload.appid], payload);
this.emit('change');
} else if (data.type === 'DELETE_MESSAGES') {
const id = data.payload;
const id = payload;
if (id === -1) {
this.appToMessages = {};
} else {
delete this.appToMessages[-1];
delete this.appToMessages[id];
}
this.reset = 0;
this.emit('change');
}
}
removeFromList(messages, messageToDelete) {
if (messages) {
const index = messages.messages.findIndex((message) => message.id === messageToDelete.id);
if (index !== -1) {
messages.messages.splice(index, 1);
return index;
}
}
return false;
}
updateApps = () => {
const appToUrl = {};
AppStore.get().forEach((app) => appToUrl[app.id] = app.image);