Skip to content

Convert App to a function component. #2308

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Nov 30, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 43 additions & 63 deletions client/modules/App/App.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import PropTypes from 'prop-types';
import React from 'react';
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';
import React, { useEffect, useRef, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useLocation } from 'react-router-dom';
import getConfig from '../../utils/getConfig';
import DevTools from './components/DevTools';
import { setPreviousPath } from '../IDE/actions/ide';
Expand All @@ -15,77 +15,57 @@ function hideCookieConsent(pathname) {
return false;
}

class App extends React.Component {
constructor(props, context) {
super(props, context);
this.state = { isMounted: false };
}
const App = ({ children }) => {
const dispatch = useDispatch();

componentDidMount() {
this.setState({ isMounted: true }); // eslint-disable-line react/no-did-mount-set-state
document.body.className = this.props.theme;
}
const location = useLocation();

componentWillReceiveProps(nextProps) {
const locationWillChange = nextProps.location !== this.props.location;
const shouldSkipRemembering =
nextProps.location.state &&
nextProps.location.state.skipSavingPath === true;
const theme = useSelector((state) => state.preferences.theme);
useEffect(() => {
document.body.className = theme;
}, [theme]);

if (locationWillChange && !shouldSkipRemembering) {
this.props.setPreviousPath(this.props.location.pathname);
}
// TODO: this is only needed for the initial load and would be better handled elsewhere - Linda
const language = useSelector((state) => state.preferences.language);
useEffect(() => {
dispatch(setLanguage(language, { persistPreference: false }));
}, [language]);

if (this.props.language !== nextProps.language) {
this.props.setLanguage(nextProps.language, { persistPreference: false });
}
}
// TODO: do we actually need this? - Linda
const [isMounted, setIsMounted] = useState(false);
useEffect(() => setIsMounted(true), []);

const previousLocationRef = useRef(location);
useEffect(() => {
const prevLocation = previousLocationRef.current;
const locationChanged = prevLocation && prevLocation !== location;
const shouldSkipRemembering = location.state?.skipSavingPath === true;

componentDidUpdate(prevProps) {
if (this.props.theme !== prevProps.theme) {
document.body.className = this.props.theme;
if (locationChanged && !shouldSkipRemembering) {
dispatch(setPreviousPath(prevLocation.pathname));
}
}
previousLocationRef.current = location;
}, [location]);

render() {
const hide = hideCookieConsent(this.props.location.pathname);
return (
<div className="app">
<CookieConsent hide={hide} />
{this.state.isMounted &&
!window.devToolsExtension &&
getConfig('NODE_ENV') === 'development' && <DevTools />}
{this.props.children}
</div>
);
}
}
const hide = hideCookieConsent(location.pathname);

return (
<div className="app">
<CookieConsent hide={hide} />
{isMounted &&
!window.devToolsExtension &&
getConfig('NODE_ENV') === 'development' && <DevTools />}
{children}
</div>
);
};

App.propTypes = {
children: PropTypes.element,
location: PropTypes.shape({
pathname: PropTypes.string,
state: PropTypes.shape({
skipSavingPath: PropTypes.bool
})
}).isRequired,
setPreviousPath: PropTypes.func.isRequired,
setLanguage: PropTypes.func.isRequired,
language: PropTypes.string,
theme: PropTypes.string
children: PropTypes.element
};

App.defaultProps = {
children: null,
language: null,
theme: 'light'
children: null
};

const mapStateToProps = (state) => ({
theme: state.preferences.theme,
language: state.preferences.language
});

const mapDispatchToProps = { setPreviousPath, setLanguage };

export default withRouter(connect(mapStateToProps, mapDispatchToProps)(App));
export default App;