Skip to content

Commit cf9e165

Browse files
authored
Merge pull request scratchfoundation#4676 from mzgoddard/menu-bar
Move projectChanged into HOC wrapping MenuBar, to avoid unnecessary renders
2 parents e877486 + fc8c242 commit cf9e165

File tree

2 files changed

+63
-12
lines changed

2 files changed

+63
-12
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import {connect} from 'react-redux';
2+
import PropTypes from 'prop-types';
3+
import bindAll from 'lodash.bindall';
4+
import React from 'react';
5+
6+
const ConfirmReplaceHOC = function (WrappedComponent) {
7+
class ConfirmReplaceProject extends React.PureComponent {
8+
constructor (props) {
9+
super(props);
10+
11+
bindAll(this, [
12+
'confirmReadyToReplaceProject'
13+
]);
14+
}
15+
16+
confirmReadyToReplaceProject (message) {
17+
let readyToReplaceProject = true;
18+
if (this.props.projectChanged && !this.props.canCreateNew) {
19+
readyToReplaceProject = confirm(message); // eslint-disable-line no-alert
20+
}
21+
return readyToReplaceProject;
22+
}
23+
24+
render () {
25+
const {
26+
/* eslint-disable no-unused-vars */
27+
projectChanged,
28+
/* eslint-enable no-unused-vars */
29+
...props
30+
} = this.props;
31+
return (<WrappedComponent
32+
confirmReadyToReplaceProject={this.confirmReadyToReplaceProject}
33+
{...props}
34+
/>);
35+
}
36+
}
37+
38+
ConfirmReplaceProject.propTypes = {
39+
canCreateNew: PropTypes.bool,
40+
projectChanged: PropTypes.bool
41+
};
42+
43+
const _mapStateToProps = state => ({
44+
projectChanged: state.scratchGui.projectChanged
45+
});
46+
47+
return connect(_mapStateToProps)(ConfirmReplaceProject);
48+
};
49+
50+
export default ConfirmReplaceHOC;

src/components/menu-bar/menu-bar.jsx

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import classNames from 'classnames';
22
import {connect} from 'react-redux';
3+
import {compose} from 'redux';
34
import {defineMessages, FormattedMessage, injectIntl, intlShape} from 'react-intl';
45
import PropTypes from 'prop-types';
56
import bindAll from 'lodash.bindall';
@@ -27,6 +28,7 @@ import LoginDropdown from './login-dropdown.jsx';
2728
import SB3Downloader from '../../containers/sb3-downloader.jsx';
2829
import DeletionRestorer from '../../containers/deletion-restorer.jsx';
2930
import TurboMode from '../../containers/turbo-mode.jsx';
31+
import ConfirmReplaceHOC from './confirm-replace-hoc.jsx';
3032

3133
import {openTipsLibrary} from '../../reducers/modals';
3234
import {setPlayer} from '../../reducers/mode';
@@ -164,17 +166,14 @@ class MenuBar extends React.Component {
164166
document.removeEventListener('keydown', this.handleKeyPress);
165167
}
166168
handleClickNew () {
167-
let readyToReplaceProject = true;
168169
// if the project is dirty, and user owns the project, we will autosave.
169170
// but if they are not logged in and can't save, user should consider
170171
// downloading or logging in first.
171172
// Note that if user is logged in and editing someone else's project,
172173
// they'll lose their work.
173-
if (this.props.projectChanged && !this.props.canCreateNew) {
174-
readyToReplaceProject = confirm( // eslint-disable-line no-alert
175-
this.props.intl.formatMessage(sharedMessages.replaceProjectWarning)
176-
);
177-
}
174+
const readyToReplaceProject = this.props.confirmReadyToReplaceProject(
175+
this.props.intl.formatMessage(sharedMessages.replaceProjectWarning)
176+
);
178177
this.props.onRequestCloseFile();
179178
if (readyToReplaceProject) {
180179
this.props.onClickNew(this.props.canSave && this.props.canCreateNew);
@@ -759,7 +758,6 @@ MenuBar.propTypes = {
759758
onShare: PropTypes.func,
760759
onToggleLoginOpen: PropTypes.func,
761760
onUpdateProjectTitle: PropTypes.func,
762-
projectChanged: PropTypes.bool,
763761
projectTitle: PropTypes.string,
764762
renderLogin: PropTypes.func,
765763
sessionExists: PropTypes.bool,
@@ -785,7 +783,6 @@ const mapStateToProps = (state, ownProps) => {
785783
languageMenuOpen: languageMenuOpen(state),
786784
locale: state.locales.locale,
787785
loginMenuOpen: loginMenuOpen(state),
788-
projectChanged: state.scratchGui.projectChanged,
789786
projectTitle: state.scratchGui.projectTitle,
790787
sessionExists: state.session && typeof state.session.session !== 'undefined',
791788
username: user ? user.username : null,
@@ -815,7 +812,11 @@ const mapDispatchToProps = dispatch => ({
815812
onSeeCommunity: () => dispatch(setPlayer(true))
816813
});
817814

818-
export default injectIntl(connect(
819-
mapStateToProps,
820-
mapDispatchToProps
821-
)(MenuBar));
815+
export default compose(
816+
injectIntl,
817+
ConfirmReplaceHOC,
818+
connect(
819+
mapStateToProps,
820+
mapDispatchToProps
821+
)
822+
)(MenuBar);

0 commit comments

Comments
 (0)