Remove usage of react-infinite-any-height

This module uses the index as key, this is bad, because we have a real
id for identifying messages.
see https://reactjs.org/docs/lists-and-keys.html
This commit is contained in:
Jannis Mattheis 2018-10-26 21:06:19 +02:00
parent 120e41ff91
commit 1a9132e5a0
4 changed files with 187 additions and 41 deletions

130
ui/package-lock.json generated
View File

@ -280,6 +280,15 @@
"@types/react": "*" "@types/react": "*"
} }
}, },
"@types/react-infinite": {
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/@types/react-infinite/-/react-infinite-0.0.33.tgz",
"integrity": "sha512-9fVHtg811uRRqssb093qp/eIPsMroTxltv/xfOaOjdYZPndSFi7q6zxOcOVPlqVrCNjaE6JMm3z2/3LzRt0Y1g==",
"dev": true,
"requires": {
"@types/react": "*"
}
},
"@types/react-router": { "@types/react-router": {
"version": "4.0.30", "version": "4.0.30",
"resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-4.0.30.tgz", "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-4.0.30.tgz",
@ -3257,6 +3266,30 @@
"resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz",
"integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=" "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA="
}, },
"enzyme-adapter-react-16": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.1.1.tgz",
"integrity": "sha512-kC8pAtU2Jk3OJ0EG8Y2813dg9Ol0TXi7UNxHzHiWs30Jo/hj7alc//G1YpKUsPP1oKl9X+Lkx+WlGJpPYA+nvw==",
"requires": {
"enzyme-adapter-utils": "^1.3.0",
"lodash": "^4.17.4",
"object.assign": "^4.0.4",
"object.values": "^1.0.4",
"prop-types": "^15.6.0",
"react-reconciler": "^0.7.0",
"react-test-renderer": "^16.0.0-0"
}
},
"enzyme-adapter-utils": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/enzyme-adapter-utils/-/enzyme-adapter-utils-1.8.1.tgz",
"integrity": "sha512-s3QB3xQAowaDS2sHhmEqrT13GJC4+n5bG015ZkLv60n9k5vhxxHTQRIneZmQ4hmdCZEBrvUJ89PG6fRI5OEeuQ==",
"requires": {
"function.prototype.name": "^1.1.0",
"object.assign": "^4.1.0",
"prop-types": "^15.6.2"
}
},
"errno": { "errno": {
"version": "0.1.7", "version": "0.1.7",
"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz",
@ -4531,6 +4564,16 @@
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
}, },
"function.prototype.name": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.0.tgz",
"integrity": "sha512-Bs0VRrTz4ghD8pTmbJQD1mZ8A/mN0ur/jGz+A6FBxPDUPkm1tNfF6bhTYPA7i7aF4lZJVr+OXTNNrnnIl58Wfg==",
"requires": {
"define-properties": "^1.1.2",
"function-bind": "^1.1.1",
"is-callable": "^1.1.3"
}
},
"get-caller-file": { "get-caller-file": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
@ -4784,6 +4827,11 @@
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
}, },
"has-symbols": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz",
"integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q="
},
"has-value": { "has-value": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
@ -7613,6 +7661,17 @@
"isobject": "^3.0.0" "isobject": "^3.0.0"
} }
}, },
"object.assign": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz",
"integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==",
"requires": {
"define-properties": "^1.1.2",
"function-bind": "^1.1.1",
"has-symbols": "^1.0.0",
"object-keys": "^1.0.11"
}
},
"object.getownpropertydescriptors": { "object.getownpropertydescriptors": {
"version": "2.0.3", "version": "2.0.3",
"resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz",
@ -7639,6 +7698,17 @@
"isobject": "^3.0.1" "isobject": "^3.0.1"
} }
}, },
"object.values": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/object.values/-/object.values-1.0.4.tgz",
"integrity": "sha1-5STaCbT2b/Bd9FdUbscqyZ8TBpo=",
"requires": {
"define-properties": "^1.1.2",
"es-abstract": "^1.6.1",
"function-bind": "^1.1.0",
"has": "^1.0.1"
}
},
"obuf": { "obuf": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz",
@ -9554,10 +9624,11 @@
} }
}, },
"react-infinite": { "react-infinite": {
"version": "0.12.1", "version": "0.13.0",
"resolved": "https://registry.npmjs.org/react-infinite/-/react-infinite-0.12.1.tgz", "resolved": "https://registry.npmjs.org/react-infinite/-/react-infinite-0.13.0.tgz",
"integrity": "sha512-sOXsm0OsszFQQ+4Vtqt1UUqLETGOCS0keAdEQuNMmeoIHHz2iIW44cHhPLxyeAsdfJQOYanmBZjhpZFQw7bhKw==", "integrity": "sha512-sISd4IYKELmOrvCq9i3FaQo4HR+Bn49ufK0eYAWQAisQ87QWJ5tqiQvEzww+JJZryZVMFvBCuiV7RUn/MfeEww==",
"requires": { "requires": {
"enzyme-adapter-react-16": "1.1.1",
"lodash.isarray": "3.0.4", "lodash.isarray": "3.0.4",
"lodash.isfinite": "3.2.0", "lodash.isfinite": "3.2.0",
"object-assign": "4.0.1" "object-assign": "4.0.1"
@ -9577,7 +9648,29 @@
"requires": { "requires": {
"lodash.isequal": "^4.5.0", "lodash.isequal": "^4.5.0",
"react-infinite": "^0.12.1" "react-infinite": "^0.12.1"
},
"dependencies": {
"object-assign": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.0.1.tgz",
"integrity": "sha1-mVBEVsNZi1ytT8WcJuipuxB/4L0="
},
"react-infinite": {
"version": "0.12.1",
"resolved": "https://registry.npmjs.org/react-infinite/-/react-infinite-0.12.1.tgz",
"integrity": "sha512-sOXsm0OsszFQQ+4Vtqt1UUqLETGOCS0keAdEQuNMmeoIHHz2iIW44cHhPLxyeAsdfJQOYanmBZjhpZFQw7bhKw==",
"requires": {
"lodash.isarray": "3.0.4",
"lodash.isfinite": "3.2.0",
"object-assign": "4.0.1"
} }
}
}
},
"react-is": {
"version": "16.6.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.6.0.tgz",
"integrity": "sha512-q8U7k0Fi7oxF1HvQgyBjPwDXeMplEsArnKt2iYhuIF86+GBbgLHdAmokL3XUFjTd7Q363OSNG55FOGUdONVn1g=="
}, },
"react-jss": { "react-jss": {
"version": "8.6.1", "version": "8.6.1",
@ -9596,6 +9689,17 @@
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
}, },
"react-reconciler": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.7.0.tgz",
"integrity": "sha512-50JwZ3yNyMS8fchN+jjWEJOH3Oze7UmhxeoJLn2j6f3NjpfCRbcmih83XTWmzqtar/ivd5f7tvQhvvhism2fgg==",
"requires": {
"fbjs": "^0.8.16",
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1",
"prop-types": "^15.6.0"
}
},
"react-router": { "react-router": {
"version": "4.3.1", "version": "4.3.1",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-4.3.1.tgz", "resolved": "https://registry.npmjs.org/react-router/-/react-router-4.3.1.tgz",
@ -9703,6 +9807,17 @@
} }
} }
}, },
"react-test-renderer": {
"version": "16.6.0",
"resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-16.6.0.tgz",
"integrity": "sha512-w+Y3YT7OX1LP5KO7HCd0YR34Ol1qmISHaooPNMRYa6QzmwtcWhEGuZPr34wO8UCBIokswuhyLQUq7rjPDcEtJA==",
"requires": {
"object-assign": "^4.1.1",
"prop-types": "^15.6.2",
"react-is": "^16.6.0",
"scheduler": "^0.10.0"
}
},
"react-timeago": { "react-timeago": {
"version": "4.1.9", "version": "4.1.9",
"resolved": "https://registry.npmjs.org/react-timeago/-/react-timeago-4.1.9.tgz", "resolved": "https://registry.npmjs.org/react-timeago/-/react-timeago-4.1.9.tgz",
@ -10216,6 +10331,15 @@
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
}, },
"scheduler": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.10.0.tgz",
"integrity": "sha512-+TSTVTCBAA3h8Anei3haDc1IRwMeDmtI/y/o3iBe3Mjl2vwYF9DtPDt929HyRmV/e7au7CLu8sc4C4W0VOs29w==",
"requires": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1"
}
},
"schema-utils": { "schema-utils": {
"version": "0.3.0", "version": "0.3.0",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz",

View File

@ -14,6 +14,7 @@
"prop-types": "^15.6.2", "prop-types": "^15.6.2",
"react": "^16.4.2", "react": "^16.4.2",
"react-dom": "^16.4.2", "react-dom": "^16.4.2",
"react-infinite": "^0.13.0",
"react-infinite-any-height": "^2.3.0", "react-infinite-any-height": "^2.3.0",
"react-router": "^4.3.1", "react-router": "^4.3.1",
"react-router-dom": "^4.3.1", "react-router-dom": "^4.3.1",
@ -41,6 +42,7 @@
"@types/puppeteer": "^1.6.3", "@types/puppeteer": "^1.6.3",
"@types/react": "^16.4.11", "@types/react": "^16.4.11",
"@types/react-dom": "^16.0.7", "@types/react-dom": "^16.0.7",
"@types/react-infinite": "0.0.33",
"@types/react-router-dom": "^4.3.0", "@types/react-router-dom": "^4.3.0",
"@types/rimraf": "^2.0.2", "@types/rimraf": "^2.0.2",
"get-port": "^4.0.0", "get-port": "^4.0.0",

View File

@ -47,11 +47,19 @@ interface IProps {
date: string; date: string;
content: string; content: string;
fDelete: VoidFunction; fDelete: VoidFunction;
height: (height: number) => void;
} }
function Message({fDelete, classes, title, date, content, image}: IProps & Style) { class Message extends React.PureComponent<IProps & Style> {
private node: HTMLDivElement | null;
public componentDidMount = () =>
this.props.height(this.node ? this.node.getBoundingClientRect().height : 0);
public render(): React.ReactNode {
const {fDelete, classes, title, date, content, image} = this.props;
return ( return (
<div className={`${classes.wrapperPadding} message`}> <div className={`${classes.wrapperPadding} message`} ref={(ref) => (this.node = ref)}>
<Container style={{display: 'flex'}}> <Container style={{display: 'flex'}}>
<div className={classes.imageWrapper}> <div className={classes.imageWrapper}>
<img <img
@ -64,7 +72,9 @@ function Message({fDelete, classes, title, date, content, image}: IProps & Style
</div> </div>
<div className={classes.messageContentWrapper}> <div className={classes.messageContentWrapper}>
<div className={classes.header}> <div className={classes.header}>
<Typography className={`${classes.headerTitle} title`} variant="headline"> <Typography
className={`${classes.headerTitle} title`}
variant="headline">
{title} {title}
</Typography> </Typography>
<Typography variant="body1" className="date"> <Typography variant="body1" className="date">
@ -81,6 +91,7 @@ function Message({fDelete, classes, title, date, content, image}: IProps & Style
</Container> </Container>
</div> </div>
); );
}
} }
export default withStyles(styles)<IProps>(Message); export default withStyles(styles)<IProps>(Message);

View File

@ -6,9 +6,9 @@ import {RouteComponentProps} from 'react-router';
import DefaultPage from '../common/DefaultPage'; import DefaultPage from '../common/DefaultPage';
import Message from './Message'; import Message from './Message';
import {observer} from 'mobx-react'; import {observer} from 'mobx-react';
// @ts-ignore
import InfiniteAnyHeight from 'react-infinite-any-height';
import {inject, Stores} from '../inject'; import {inject, Stores} from '../inject';
import {observable} from 'mobx';
import ReactInfinite from 'react-infinite';
interface IProps extends RouteComponentProps<{id: string}> {} interface IProps extends RouteComponentProps<{id: string}> {}
@ -18,6 +18,9 @@ interface IState {
@observer @observer
class Messages extends Component<IProps & Stores<'messagesStore' | 'appStore'>, IState> { class Messages extends Component<IProps & Stores<'messagesStore' | 'appStore'>, IState> {
@observable
private heights: Record<number, number> = {};
private static appId(props: IProps) { private static appId(props: IProps) {
if (props === undefined) { if (props === undefined) {
return -1; return -1;
@ -63,12 +66,14 @@ class Messages extends Component<IProps & Stores<'messagesStore' | 'appStore'>,
buttonDisabled={!hasMessages}> buttonDisabled={!hasMessages}>
{hasMessages ? ( {hasMessages ? (
<div style={{width: '100%'}} id="messages"> <div style={{width: '100%'}} id="messages">
<InfiniteAnyHeight <ReactInfinite
key={appId} key={appId}
list={messages.map(this.renderMessage)}
preloadAdditionalHeight={window.innerHeight * 2.5}
useWindowAsScrollContainer useWindowAsScrollContainer
/> preloadBatchSize={window.innerHeight * 3}
elementHeight={messages.map((m) => this.heights[m.id] || 1)}>
{messages.map(this.renderMessage)}
</ReactInfinite>
{hasMore ? ( {hasMore ? (
<Grid item xs={12} style={{textAlign: 'center'}}> <Grid item xs={12} style={{textAlign: 'center'}}>
<CircularProgress size={100} /> <CircularProgress size={100} />
@ -99,10 +104,14 @@ class Messages extends Component<IProps & Stores<'messagesStore' | 'appStore'>,
this.props.messagesStore.removeSingle(message); this.props.messagesStore.removeSingle(message);
private renderMessage = (message: IMessage) => { private renderMessage = (message: IMessage) => {
this.checkIfLoadMore();
return ( return (
<Message <Message
key={message.id} key={message.id}
height={(height) => {
if (!this.heights[message.id]) {
this.heights[message.id] = height;
}
}}
fDelete={this.deleteMessage(message)} fDelete={this.deleteMessage(message)}
title={message.title} title={message.title}
date={message.date} date={message.date}