File tree 9 files changed +153
-23
lines changed
9 files changed +153
-23
lines changed Original file line number Diff line number Diff line change 1
- import React , { Component } from 'react' ;
1
+ import React , { useContext , useState , Suspense } from 'react' ;
2
2
3
3
import Chrome from './Chrome' ;
4
4
import Page from './Page' ;
5
+ import Page2 from './Page2' ;
6
+ import Theme from './Theme' ;
5
7
6
- export default class App extends Component {
7
- render ( ) {
8
- return (
9
- < Chrome title = "Hello World" assets = { this . props . assets } >
10
- < div >
11
- < h1 > Hello World</ h1 >
12
- < Page />
13
- </ div >
14
- </ Chrome >
15
- ) ;
16
- }
8
+ function LoadingIndicator ( ) {
9
+ let theme = useContext ( Theme ) ;
10
+ return < div className = { theme + '-loading' } > Loading...</ div > ;
11
+ }
12
+
13
+ export default function App ( { assets} ) {
14
+ let [ CurrentPage , switchPage ] = useState ( ( ) => Page ) ;
15
+ return (
16
+ < Chrome title = "Hello World" assets = { assets } >
17
+ < div >
18
+ < h1 > Hello World</ h1 >
19
+ < a className = "link" onClick = { ( ) => switchPage ( ( ) => Page ) } >
20
+ Page 1
21
+ </ a >
22
+ { ' | ' }
23
+ < a className = "link" onClick = { ( ) => switchPage ( ( ) => Page2 ) } >
24
+ Page 2
25
+ </ a >
26
+ < Suspense fallback = { < LoadingIndicator /> } >
27
+ < CurrentPage />
28
+ </ Suspense >
29
+ </ div >
30
+ </ Chrome >
31
+ ) ;
17
32
}
Original file line number Diff line number Diff line change 3
3
padding : 0 ;
4
4
font-family : sans-serif;
5
5
}
6
+
7
+ body .light {
8
+ background-color : # FFFFFF ;
9
+ color : # 333333 ;
10
+ }
11
+
12
+ body .dark {
13
+ background-color : # 000000 ;
14
+ color : # CCCCCC ;
15
+ }
16
+
17
+ .light-loading {
18
+ margin : 10px 0 ;
19
+ padding : 10px ;
20
+ background-color : # CCCCCC ;
21
+ color : # 666666 ;
22
+ }
23
+
24
+ .dark-loading {
25
+ margin : 10px 0 ;
26
+ padding : 10px ;
27
+ background-color : # 333333 ;
28
+ color : # 999999 ;
29
+ }
Original file line number Diff line number Diff line change 1
1
import React , { Component } from 'react' ;
2
2
3
+ import Theme , { ThemeToggleButton } from './Theme' ;
4
+
3
5
import './Chrome.css' ;
4
6
5
7
export default class Chrome extends Component {
8
+ state = { theme : 'light' } ;
6
9
render ( ) {
7
10
const assets = this . props . assets ;
8
11
return (
@@ -14,13 +17,18 @@ export default class Chrome extends Component {
14
17
< link rel = "stylesheet" href = { assets [ 'main.css' ] } />
15
18
< title > { this . props . title } </ title >
16
19
</ head >
17
- < body >
20
+ < body className = { this . state . theme } >
18
21
< noscript
19
22
dangerouslySetInnerHTML = { {
20
23
__html : `<b>Enable JavaScript to run this app.</b>` ,
21
24
} }
22
25
/>
23
- { this . props . children }
26
+ < Theme . Provider value = { this . state . theme } >
27
+ { this . props . children }
28
+ < div >
29
+ < ThemeToggleButton onChange = { theme => this . setState ( { theme} ) } />
30
+ </ div >
31
+ </ Theme . Provider >
24
32
< script
25
33
dangerouslySetInnerHTML = { {
26
34
__html : `assetManifest = ${ JSON . stringify ( assets ) } ;` ,
Original file line number Diff line number Diff line change 1
- .bold {
1
+ .link {
2
2
font-weight : bold;
3
+ cursor : pointer;
4
+ }
5
+ .light-box {
6
+ margin : 10px 0 ;
7
+ padding : 10px ;
8
+ background-color : # CCCCCC ;
9
+ color : # 333333 ;
10
+ }
11
+ .dark-box {
12
+ margin : 10px 0 ;
13
+ padding : 10px ;
14
+ background-color : # 333333 ;
15
+ color : # CCCCCC ;
3
16
}
Original file line number Diff line number Diff line change 1
1
import React , { Component } from 'react' ;
2
2
3
+ import Theme from './Theme' ;
4
+ import Suspend from './Suspend' ;
5
+
3
6
import './Page.css' ;
4
7
5
8
const autofocusedInputs = [
@@ -14,17 +17,22 @@ export default class Page extends Component {
14
17
} ;
15
18
render ( ) {
16
19
const link = (
17
- < a className = "bold " onClick = { this . handleClick } >
20
+ < a className = "link " onClick = { this . handleClick } >
18
21
Click Here
19
22
</ a >
20
23
) ;
21
24
return (
22
- < div >
23
- < p suppressHydrationWarning = { true } > A random number: { Math . random ( ) } </ p >
24
- < p > Autofocus on page load: { autofocusedInputs } </ p >
25
- < p > { ! this . state . active ? link : 'Thanks!' } </ p >
26
- { this . state . active && < p > Autofocus on update: { autofocusedInputs } </ p > }
25
+ < div className = { this . context + '-box' } >
26
+ < Suspend >
27
+ < p suppressHydrationWarning = { true } >
28
+ A random number: { Math . random ( ) }
29
+ </ p >
30
+ < p > Autofocus on page load: { autofocusedInputs } </ p >
31
+ < p > { ! this . state . active ? link : 'Thanks!' } </ p >
32
+ { this . state . active && < p > Autofocus on update: { autofocusedInputs } </ p > }
33
+ </ Suspend >
27
34
</ div >
28
35
) ;
29
36
}
30
37
}
38
+ Page . contextType = Theme ;
Original file line number Diff line number Diff line change
1
+ import React , { useContext } from 'react' ;
2
+
3
+ import Theme from './Theme' ;
4
+ import Suspend from './Suspend' ;
5
+
6
+ import './Page.css' ;
7
+
8
+ export default function Page2 ( ) {
9
+ let theme = useContext ( Theme ) ;
10
+ return (
11
+ < div className = { theme + '-box' } >
12
+ < Suspend > Content of a different page</ Suspend >
13
+ </ div >
14
+ ) ;
15
+ }
Original file line number Diff line number Diff line change
1
+ let promise = null ;
2
+ let isResolved = false ;
3
+
4
+ export default function Suspend ( { children} ) {
5
+ // This will suspend the content from rendering but only on the client.
6
+ // This is used to demo a slow loading app.
7
+ if ( typeof window === 'object' ) {
8
+ if ( ! isResolved ) {
9
+ if ( promise === null ) {
10
+ promise = new Promise ( resolve => {
11
+ setTimeout ( ( ) => {
12
+ isResolved = true ;
13
+ resolve ( ) ;
14
+ } , 6000 ) ;
15
+ } ) ;
16
+ }
17
+ throw promise ;
18
+ }
19
+ }
20
+ return children ;
21
+ }
Original file line number Diff line number Diff line change
1
+ import React , { createContext , useContext , useState } from 'react' ;
2
+
3
+ const Theme = createContext ( 'light' ) ;
4
+
5
+ export default Theme ;
6
+
7
+ export function ThemeToggleButton ( { onChange} ) {
8
+ let theme = useContext ( Theme ) ;
9
+ let [ targetTheme , setTargetTheme ] = useState ( theme ) ;
10
+ function toggleTheme ( ) {
11
+ let newTheme = theme === 'light' ? 'dark' : 'light' ;
12
+ // High pri, responsive update.
13
+ setTargetTheme ( newTheme ) ;
14
+ // Perform the actual theme change in a separate update.
15
+ setTimeout ( ( ) => onChange ( newTheme ) , 0 ) ;
16
+ }
17
+ if ( targetTheme !== theme ) {
18
+ return 'Switching to ' + targetTheme + '...' ;
19
+ }
20
+ return (
21
+ < a className = "link" onClick = { toggleTheme } >
22
+ Switch to { theme === 'light' ? 'Dark' : 'Light' } theme
23
+ </ a >
24
+ ) ;
25
+ }
Original file line number Diff line number Diff line change 1
1
import React from 'react' ;
2
- import { hydrate } from 'react-dom' ;
2
+ import { unstable_createRoot } from 'react-dom' ;
3
3
4
4
import App from './components/App' ;
5
5
6
- hydrate ( < App assets = { window . assetManifest } /> , document ) ;
6
+ let root = unstable_createRoot ( document , { hydrate : true } ) ;
7
+ root . render ( < App assets = { window . assetManifest } /> ) ;
You can’t perform that action at this time.
0 commit comments