-
Notifications
You must be signed in to change notification settings - Fork 66
/
Copy pathAppProvider.jsx
99 lines (88 loc) · 2.81 KB
/
AppProvider.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import React, { useState, useMemo } from 'react';
import PropTypes from 'prop-types';
import { BrowserRouter as Router } from 'react-router-dom';
import OptionalReduxProvider from './OptionalReduxProvider';
import ErrorBoundary from './ErrorBoundary';
import AppContext from './AppContext';
import { useAppEvent, useTrackColorSchemeChoice } from './hooks';
import { getAuthenticatedUser, AUTHENTICATED_USER_CHANGED } from '../auth';
import { getConfig } from '../config';
import { CONFIG_CHANGED } from '../constants';
import {
getLocale,
getMessages,
IntlProvider,
LOCALE_CHANGED,
} from '../i18n';
import { basename } from '../initialize';
/**
* A wrapper component for React-based micro-frontends to initialize a number of common data/
* context providers.
*
* ```
* subscribe(APP_READY, () => {
* ReactDOM.render(
* <AppProvider>
* <HelloWorld />
* </AppProvider>
* )
* });
* ```
*
* This will provide the following to HelloWorld:
* - An error boundary as described above.
* - An `AppContext` provider for React context data.
* - IntlProvider for @edx/frontend-i18n internationalization
* - Optionally a redux `Provider`. Will only be included if a `store` property is passed to
* `AppProvider`.
* - A `Router` for react-router.
*
* @param {Object} props
* @param {Object} [props.store] A redux store.
* @memberof module:React
*/
export default function AppProvider({ store, children, wrapWithRouter }) {
const [config, setConfig] = useState(getConfig());
const [authenticatedUser, setAuthenticatedUser] = useState(getAuthenticatedUser());
const [locale, setLocale] = useState(getLocale());
useTrackColorSchemeChoice();
useAppEvent(AUTHENTICATED_USER_CHANGED, () => {
setAuthenticatedUser(getAuthenticatedUser());
});
useAppEvent(CONFIG_CHANGED, () => {
setConfig(getConfig());
});
useAppEvent(LOCALE_CHANGED, () => {
setLocale(getLocale());
});
const appContextValue = useMemo(() => ({ authenticatedUser, config, locale }), [authenticatedUser, config, locale]);
return (
<IntlProvider locale={locale} messages={getMessages()}>
<ErrorBoundary>
<AppContext.Provider
value={appContextValue}
>
<OptionalReduxProvider store={store}>
{wrapWithRouter ? (
<Router basename={basename}>
<div data-testid="browser-router">
{children}
</div>
</Router>
) : children}
</OptionalReduxProvider>
</AppContext.Provider>
</ErrorBoundary>
</IntlProvider>
);
}
AppProvider.propTypes = {
// eslint-disable-next-line react/forbid-prop-types
store: PropTypes.object,
children: PropTypes.node.isRequired,
wrapWithRouter: PropTypes.bool,
};
AppProvider.defaultProps = {
store: null,
wrapWithRouter: true,
};