Improving Performance Part 2 (#1010)
* Remove serverVersion check to allow GitLab login * Avoid unncessary re-renders on the root screen * Avoid unncessary re-renders on the options modal screen * Avoid unncessary re-renders on the thread screen * Avoid unncessary re-renders on the offline indicator component * Avoid unncessary re-renders on the channel loader component * review feedback
This commit is contained in:
parent
dabad3eca6
commit
f8414559b2
9 changed files with 59 additions and 99 deletions
|
|
@ -6,10 +6,9 @@ import {getTheme} from 'app/selectors/preferences';
|
|||
|
||||
import ChannelLoader from './channel_loader';
|
||||
|
||||
function mapStateToProps(state, ownProps) {
|
||||
function mapStateToProps(state) {
|
||||
const {deviceWidth} = state.device.dimension;
|
||||
return {
|
||||
...ownProps,
|
||||
channelIsLoading: state.views.channel.loading,
|
||||
deviceWidth,
|
||||
theme: getTheme(state)
|
||||
|
|
|
|||
|
|
@ -1,37 +1,22 @@
|
|||
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import {bindActionCreators} from 'redux';
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import {close as closeWebSocket, init as initWebSocket} from 'mattermost-redux/actions/websocket';
|
||||
|
||||
import {getConnection} from 'app/selectors/device';
|
||||
|
||||
import OfflineIndicator from './offline_indicator';
|
||||
|
||||
function mapStateToProps(state, ownProps) {
|
||||
function mapStateToProps(state) {
|
||||
const {websocket} = state.requests.general;
|
||||
const {appState} = state.entities.general;
|
||||
const webSocketStatus = websocket.status;
|
||||
const isConnecting = websocket.error >= 2;
|
||||
const isConnecting = websocket.error > 1;
|
||||
|
||||
return {
|
||||
appState,
|
||||
isConnecting,
|
||||
isOnline: getConnection(state),
|
||||
webSocketStatus,
|
||||
...ownProps
|
||||
webSocketStatus
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators({
|
||||
closeWebSocket,
|
||||
initWebSocket
|
||||
}, dispatch)
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(OfflineIndicator);
|
||||
export default connect(mapStateToProps)(OfflineIndicator);
|
||||
|
|
|
|||
|
|
@ -1,14 +1,13 @@
|
|||
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import React, {PureComponent} from 'react';
|
||||
import React, {Component} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
ActivityIndicator,
|
||||
Animated,
|
||||
Platform,
|
||||
StyleSheet,
|
||||
TouchableOpacity,
|
||||
View
|
||||
} from 'react-native';
|
||||
import IonIcon from 'react-native-vector-icons/Ionicons';
|
||||
|
|
@ -24,20 +23,14 @@ const OFFLINE = 'offline';
|
|||
const CONNECTING = 'connecting';
|
||||
const CONNECTED = 'connected';
|
||||
|
||||
export default class OfflineIndicator extends PureComponent {
|
||||
export default class OfflineIndicator extends Component {
|
||||
static propTypes = {
|
||||
actions: PropTypes.shape({
|
||||
closeWebSocket: PropTypes.func.isRequired,
|
||||
initWebSocket: PropTypes.func.isRequired
|
||||
}).isRequired,
|
||||
appState: PropTypes.bool,
|
||||
isConnecting: PropTypes.bool,
|
||||
isOnline: PropTypes.bool,
|
||||
webSocketStatus: PropTypes.string
|
||||
};
|
||||
|
||||
static defaultProps: {
|
||||
appState: true,
|
||||
isOnline: true
|
||||
};
|
||||
|
||||
|
|
@ -53,42 +46,30 @@ export default class OfflineIndicator extends PureComponent {
|
|||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
const {appState, isConnecting, isOnline, webSocketStatus} = nextProps;
|
||||
if (appState) { // The app is in the foreground
|
||||
if (isOnline) {
|
||||
if (this.state.network && webSocketStatus === RequestStatus.SUCCESS) {
|
||||
// Show the connected animation only if we had a previous network status
|
||||
this.connected();
|
||||
} else if ((webSocketStatus === RequestStatus.STARTED || webSocketStatus === RequestStatus.FAILURE) && isConnecting) {
|
||||
// Show the connecting bar if it failed to connect at least twice
|
||||
this.connecting();
|
||||
}
|
||||
} else {
|
||||
this.offline();
|
||||
const {webSocketStatus} = this.props;
|
||||
if (nextProps.isOnline) {
|
||||
if (this.state.network && webSocketStatus === RequestStatus.STARTED && nextProps.webSocketStatus === RequestStatus.SUCCESS) {
|
||||
// Show the connected animation only if we had a previous network status
|
||||
this.connected();
|
||||
} else if (webSocketStatus === RequestStatus.STARTED && nextProps.webSocketStatus === RequestStatus.FAILURE && nextProps.isConnecting) {
|
||||
// Show the connecting bar if it failed to connect at least twice
|
||||
this.connecting();
|
||||
}
|
||||
} else {
|
||||
this.offline();
|
||||
}
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
return nextState.network !== this.state.network && nextState.network;
|
||||
}
|
||||
|
||||
offline = () => {
|
||||
this.setState({network: OFFLINE}, () => {
|
||||
this.show();
|
||||
});
|
||||
};
|
||||
|
||||
connect = () => {
|
||||
const {actions, isOnline, webSocketStatus} = this.props;
|
||||
const {closeWebSocket, initWebSocket} = actions;
|
||||
initWebSocket(Platform.OS);
|
||||
|
||||
// close the WS connection after trying for 5 seconds
|
||||
setTimeout(() => {
|
||||
if (webSocketStatus !== RequestStatus.SUCCESS) {
|
||||
closeWebSocket(true);
|
||||
this.setState({network: isOnline ? OFFLINE : CONNECTING});
|
||||
}
|
||||
}, 5000);
|
||||
};
|
||||
|
||||
connecting = () => {
|
||||
const prevState = this.state.network;
|
||||
this.setState({network: CONNECTING}, () => {
|
||||
|
|
@ -111,7 +92,7 @@ export default class OfflineIndicator extends PureComponent {
|
|||
this.state.top, {
|
||||
toValue: INITIAL_TOP,
|
||||
duration: 300,
|
||||
delay: 1000
|
||||
delay: 500
|
||||
}
|
||||
)
|
||||
]).start(() => {
|
||||
|
|
@ -146,18 +127,6 @@ export default class OfflineIndicator extends PureComponent {
|
|||
case OFFLINE:
|
||||
i18nId = 'mobile.offlineIndicator.offline';
|
||||
defaultMessage = 'No internet connection';
|
||||
action = (
|
||||
<TouchableOpacity
|
||||
onPress={this.connect}
|
||||
style={[styles.actionContainer, styles.actionButton]}
|
||||
>
|
||||
<IonIcon
|
||||
color='#FFFFFF'
|
||||
name='ios-refresh'
|
||||
size={20}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
break;
|
||||
case CONNECTING:
|
||||
i18nId = 'mobile.offlineIndicator.connecting';
|
||||
|
|
|
|||
|
|
@ -7,9 +7,8 @@ import {getDimensions} from 'app/selectors/device';
|
|||
|
||||
import OptionsModal from './options_modal';
|
||||
|
||||
function mapStateToProps(state, ownProps) {
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
...ownProps,
|
||||
...getDimensions(state)
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,11 +10,9 @@ import {getTheme} from 'app/selectors/preferences';
|
|||
|
||||
import Root from './root';
|
||||
|
||||
function mapStateToProps(state, ownProps) {
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
...ownProps,
|
||||
credentials: state.entities.general.credentials,
|
||||
loginRequest: state.requests.users.login,
|
||||
theme: getTheme(state)
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,19 @@
|
|||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import React, {PureComponent} from 'react';
|
||||
import React, {Component} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import {Client, Client4} from 'mattermost-redux/client';
|
||||
import {RequestStatus} from 'mattermost-redux/constants';
|
||||
|
||||
import Loading from 'app/components/loading';
|
||||
import {stripTrailingSlashes} from 'app/utils/url';
|
||||
|
||||
export default class Root extends PureComponent {
|
||||
export default class Root extends Component {
|
||||
static propTypes = {
|
||||
allowOtherServers: PropTypes.bool,
|
||||
credentials: PropTypes.object,
|
||||
justInit: PropTypes.bool,
|
||||
loginRequest: PropTypes.object,
|
||||
navigator: PropTypes.object,
|
||||
theme: PropTypes.object,
|
||||
actions: PropTypes.shape({
|
||||
|
|
@ -23,6 +21,13 @@ export default class Root extends PureComponent {
|
|||
}).isRequired
|
||||
};
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
if (nextProps.credentials !== this.props.credentials) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (!this.props.justInit) {
|
||||
this.loadStoreAndScene();
|
||||
|
|
@ -66,21 +71,15 @@ export default class Root extends PureComponent {
|
|||
};
|
||||
|
||||
loadStoreAndScene = () => {
|
||||
const {actions, credentials, loginRequest} = this.props;
|
||||
const {actions, credentials} = this.props;
|
||||
const {loadMe} = actions;
|
||||
if (credentials.token && credentials.url) {
|
||||
// Will probably need to make this optimistic since we
|
||||
// assume that the stored token is good.
|
||||
if (loginRequest.status === RequestStatus.NOT_STARTED) {
|
||||
Client.setToken(credentials.token);
|
||||
Client4.setToken(credentials.token);
|
||||
Client4.setUrl(stripTrailingSlashes(credentials.url));
|
||||
Client.setUrl(stripTrailingSlashes(credentials.url));
|
||||
Client.setToken(credentials.token);
|
||||
Client4.setToken(credentials.token);
|
||||
Client4.setUrl(stripTrailingSlashes(credentials.url));
|
||||
Client.setUrl(stripTrailingSlashes(credentials.url));
|
||||
|
||||
loadMe().then(this.goToLoadTeam).catch(this.goToLoadTeam);
|
||||
} else {
|
||||
this.goToLoadTeam();
|
||||
}
|
||||
loadMe().then(this.goToLoadTeam).catch(this.goToLoadTeam);
|
||||
} else {
|
||||
this.goToSelectServer();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import SelectServer from './select_server';
|
|||
|
||||
function mapStateToProps(state) {
|
||||
const {config: configRequest, license: licenseRequest, server: pingRequest} = state.requests.general;
|
||||
const {config, license, serverVersion} = state.entities.general;
|
||||
const {config, license} = state.entities.general;
|
||||
|
||||
const success = RequestStatus.SUCCESS;
|
||||
const transition = (pingRequest.status === success && configRequest.status === success && licenseRequest.status === success);
|
||||
|
|
@ -26,7 +26,6 @@ function mapStateToProps(state) {
|
|||
licenseRequest,
|
||||
config,
|
||||
license,
|
||||
serverVersion,
|
||||
transition,
|
||||
theme: getTheme(state)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ import {
|
|||
View
|
||||
} from 'react-native';
|
||||
import Button from 'react-native-button';
|
||||
import semver from 'semver';
|
||||
|
||||
import {RequestStatus} from 'mattermost-redux/constants';
|
||||
import {Client, Client4} from 'mattermost-redux/client';
|
||||
|
|
@ -43,7 +42,6 @@ class SelectServer extends PureComponent {
|
|||
pingRequest: PropTypes.object.isRequired,
|
||||
configRequest: PropTypes.object.isRequired,
|
||||
licenseRequest: PropTypes.object.isRequired,
|
||||
serverVersion: PropTypes.string.isRequired,
|
||||
actions: PropTypes.shape({
|
||||
getPing: PropTypes.func.isRequired,
|
||||
resetPing: PropTypes.func.isRequired,
|
||||
|
|
@ -85,10 +83,9 @@ class SelectServer extends PureComponent {
|
|||
}
|
||||
|
||||
handleLoginOptions = () => {
|
||||
const {config, intl, license, serverVersion, theme} = this.props;
|
||||
const version = serverVersion.match(/^[0-9]*.[0-9]*.[0-9]*(-[a-zA-Z0-9.-]*)?/g)[0];
|
||||
const {config, intl, license, theme} = this.props;
|
||||
const samlEnabled = config.EnableSaml === 'true' && license.IsLicensed === 'true' && license.SAML === 'true';
|
||||
const gitlabEnabled = config.EnableSignUpWithGitLab === 'true' && semver.valid(version) && semver.gte(version, 'v3.10.0');
|
||||
const gitlabEnabled = config.EnableSignUpWithGitLab === 'true';
|
||||
|
||||
let options = 0;
|
||||
if (samlEnabled || gitlabEnabled) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import React, {PureComponent} from 'react';
|
||||
import React, {Component} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import KeyboardLayout from 'app/components/layout/keyboard_layout';
|
||||
|
|
@ -10,7 +10,7 @@ import PostTextbox from 'app/components/post_textbox';
|
|||
import StatusBar from 'app/components/status_bar';
|
||||
import {makeStyleSheetFromTheme} from 'app/utils/theme';
|
||||
|
||||
export default class Thread extends PureComponent {
|
||||
export default class Thread extends Component {
|
||||
static propTypes = {
|
||||
actions: PropTypes.shape({
|
||||
selectPost: PropTypes.func.isRequired
|
||||
|
|
@ -25,6 +25,21 @@ export default class Thread extends PureComponent {
|
|||
|
||||
state = {};
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
if (nextProps.posts.length !== this.props.posts.length) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const length = nextProps.posts.length;
|
||||
for (let i = 0; i < length; i++) {
|
||||
if (nextProps.posts[i].id !== this.props.posts[i].id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (!this.state.lastViewedAt) {
|
||||
this.setState({lastViewedAt: nextProps.myMember.last_viewed_at});
|
||||
|
|
|
|||
Loading…
Reference in a new issue