1
1
import PropTypes from 'prop-types' ;
2
- import React from 'react' ;
3
- import { connect } from 'react-redux' ;
2
+ import React , { useEffect , useRef , useState } from 'react' ;
3
+ import { useDispatch , useSelector } from 'react-redux' ;
4
4
import getConfig from '../../utils/getConfig' ;
5
5
import DevTools from './components/DevTools' ;
6
6
import { setPreviousPath } from '../IDE/actions/ide' ;
@@ -14,51 +14,50 @@ function hideCookieConsent(pathname) {
14
14
return false ;
15
15
}
16
16
17
- class App extends React . Component {
18
- constructor ( props , context ) {
19
- super ( props , context ) ;
20
- this . state = { isMounted : false } ;
21
- }
17
+ // TODO: get location from `useLocation` after upgrading react-router to v5.
18
+ const App = ( { children, location } ) => {
19
+ const dispatch = useDispatch ( ) ;
22
20
23
- componentDidMount ( ) {
24
- this . setState ( { isMounted : true } ) ; // eslint-disable-line react/no-did-mount-set-state
25
- document . body . className = this . props . theme ;
26
- }
21
+ const theme = useSelector ( ( state ) => state . preferences . theme ) ;
22
+ useEffect ( ( ) => {
23
+ document . body . className = theme ;
24
+ } , [ theme ] ) ;
27
25
28
- componentWillReceiveProps ( nextProps ) {
29
- const locationWillChange = nextProps . location !== this . props . location ;
30
- const shouldSkipRemembering =
31
- nextProps . location . state &&
32
- nextProps . location . state . skipSavingPath === true ;
26
+ // TODO: this is only needed for the initial load and would be better handled elsewhere - Linda
27
+ const language = useSelector ( ( state ) => state . preferences . language ) ;
28
+ useEffect ( ( ) => {
29
+ dispatch ( setLanguage ( language , { persistPreference : false } ) ) ;
30
+ } , [ language ] ) ;
33
31
34
- if ( locationWillChange && ! shouldSkipRemembering ) {
35
- this . props . setPreviousPath ( this . props . location . pathname ) ;
36
- }
32
+ // TODO: do we actually need this? - Linda
33
+ const [ isMounted , setIsMounted ] = useState ( false ) ;
34
+ useEffect ( ( ) => setIsMounted ( true ) , [ ] ) ;
37
35
38
- if ( this . props . language !== nextProps . language ) {
39
- this . props . setLanguage ( nextProps . language , { persistPreference : false } ) ;
40
- }
41
- }
36
+ const previousLocationRef = useRef ( location ) ;
37
+ useEffect ( ( ) => {
38
+ const prevLocation = previousLocationRef . current ;
39
+ const locationChanged =
40
+ prevLocation && prevLocation . pathname !== location . pathname ;
41
+ const shouldSkipRemembering = location . state ?. skipSavingPath === true ;
42
42
43
- componentDidUpdate ( prevProps ) {
44
- if ( this . props . theme !== prevProps . theme ) {
45
- document . body . className = this . props . theme ;
43
+ if ( locationChanged && ! shouldSkipRemembering ) {
44
+ dispatch ( setPreviousPath ( location . pathname ) ) ;
46
45
}
47
- }
46
+ previousLocationRef . current = location ;
47
+ } , [ location ] ) ;
48
48
49
- render ( ) {
50
- const hide = hideCookieConsent ( this . props . location . pathname ) ;
51
- return (
52
- < div className = "app" >
53
- < CookieConsent hide = { hide } />
54
- { this . state . isMounted &&
55
- ! window . devToolsExtension &&
56
- getConfig ( 'NODE_ENV' ) === 'development' && < DevTools /> }
57
- { this . props . children }
58
- </ div >
59
- ) ;
60
- }
61
- }
49
+ const hide = hideCookieConsent ( location . pathname ) ;
50
+
51
+ return (
52
+ < div className = "app" >
53
+ < CookieConsent hide = { hide } />
54
+ { isMounted &&
55
+ ! window . devToolsExtension &&
56
+ getConfig ( 'NODE_ENV' ) === 'development' && < DevTools /> }
57
+ { children }
58
+ </ div >
59
+ ) ;
60
+ } ;
62
61
63
62
App . propTypes = {
64
63
children : PropTypes . element ,
@@ -67,24 +66,11 @@ App.propTypes = {
67
66
state : PropTypes . shape ( {
68
67
skipSavingPath : PropTypes . bool
69
68
} )
70
- } ) . isRequired ,
71
- setPreviousPath : PropTypes . func . isRequired ,
72
- setLanguage : PropTypes . func . isRequired ,
73
- language : PropTypes . string ,
74
- theme : PropTypes . string
69
+ } ) . isRequired
75
70
} ;
76
71
77
72
App . defaultProps = {
78
- children : null ,
79
- language : null ,
80
- theme : 'light'
73
+ children : null
81
74
} ;
82
75
83
- const mapStateToProps = ( state ) => ( {
84
- theme : state . preferences . theme ,
85
- language : state . preferences . language
86
- } ) ;
87
-
88
- const mapDispatchToProps = { setPreviousPath, setLanguage } ;
89
-
90
- export default connect ( mapStateToProps , mapDispatchToProps ) ( App ) ;
76
+ export default App ;
0 commit comments