Skip to content

Commit

Permalink
add sync external exercise
Browse files Browse the repository at this point in the history
  • Loading branch information
kentcdodds committed Feb 23, 2024
1 parent f456fd7 commit e06dd63
Show file tree
Hide file tree
Showing 10 changed files with 127 additions and 117 deletions.
24 changes: 0 additions & 24 deletions exercises/09.sync-external/01.problem/index.css

This file was deleted.

24 changes: 0 additions & 24 deletions exercises/09.sync-external/01.solution/index.css

This file was deleted.

24 changes: 0 additions & 24 deletions exercises/09.sync-external/02.problem/index.css

This file was deleted.

24 changes: 0 additions & 24 deletions exercises/09.sync-external/02.solution/index.css

This file was deleted.

26 changes: 20 additions & 6 deletions exercises/09.sync-external/02.solution/index.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,28 @@
import { useSyncExternalStore } from 'react'
import * as ReactDOM from 'react-dom/client'
import { makeMediaQueryStore } from './narrow-media-query'

const narrowScreenStore = makeMediaQueryStore('(max-width: 600px)')
export function makeMediaQueryStore(mediaQuery: string) {
function getSnapshot() {
return window.matchMedia(mediaQuery).matches
}

function subscribe(callback: () => void) {
const mediaQueryList = window.matchMedia(mediaQuery)
mediaQueryList.addEventListener('change', callback)
return () => {
mediaQueryList.removeEventListener('change', callback)
}
}

return function useMediaQuery() {
return useSyncExternalStore(subscribe, getSnapshot)
}
}

const useNarrowMediaQuery = makeMediaQueryStore('(max-width: 600px)')

function NarrowScreenNotifier() {
const isNarrow = useSyncExternalStore(
narrowScreenStore.subscribe,
narrowScreenStore.getSnapshot,
)
const isNarrow = useNarrowMediaQuery()
return isNarrow ? 'You are on a narrow screen' : 'You are on a wide screen'
}

Expand Down
15 changes: 0 additions & 15 deletions exercises/09.sync-external/02.solution/narrow-media-query.ts

This file was deleted.

1 change: 1 addition & 0 deletions exercises/09.sync-external/03.problem/README.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Make Store Utility
51 changes: 51 additions & 0 deletions exercises/09.sync-external/03.problem/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { useSyncExternalStore } from 'react'
import * as ReactDOM from 'react-dom/client'

export function makeMediaQueryStore(mediaQuery: string) {
function getSnapshot() {
return window.matchMedia(mediaQuery).matches
}

function subscribe(callback: () => void) {
const mediaQueryList = window.matchMedia(mediaQuery)
mediaQueryList.addEventListener('change', callback)
return () => {
mediaQueryList.removeEventListener('change', callback)
}
}

return function useMediaQuery() {
return useSyncExternalStore(subscribe, getSnapshot)
}
}

const useNarrowMediaQuery = makeMediaQueryStore('(max-width: 600px)')

function NarrowScreenNotifier() {
const isNarrow = useNarrowMediaQuery()
return isNarrow ? 'You are on a narrow screen' : 'You are on a wide screen'
}

function App() {
return (
<div>
<div>This is your narrow screen state:</div>
{/* 🐨 add a Suspense component around this with a fallback prop */}
<NarrowScreenNotifier />
</div>
)
}

const rootEl = document.createElement('div')
document.body.append(rootEl)
// 🦉 here's how we pretend we're server-rendering
rootEl.innerHTML = (await import('react-dom/server')).renderToString(<App />)

// 🦉 here's how we simulate a delay in hydrating with client-side js
await new Promise(resolve => setTimeout(resolve, 1000))

ReactDOM.hydrateRoot(rootEl, <App />, {
// 💯 if you want to silence the error add a onRecoverableError function here
// and if the error includes 'Missing getServerSnapshot' then return early
// otherwise log the error so you don't miss any other errors.
})
1 change: 1 addition & 0 deletions exercises/09.sync-external/03.solution/README.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Make Store Utility
54 changes: 54 additions & 0 deletions exercises/09.sync-external/03.solution/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { Suspense, useSyncExternalStore } from 'react'
import * as ReactDOM from 'react-dom/client'

export function makeMediaQueryStore(mediaQuery: string) {
function getSnapshot() {
return window.matchMedia(mediaQuery).matches
}

function subscribe(callback: () => void) {
const mediaQueryList = window.matchMedia(mediaQuery)
mediaQueryList.addEventListener('change', callback)
return () => {
mediaQueryList.removeEventListener('change', callback)
}
}

return function useMediaQuery() {
return useSyncExternalStore(subscribe, getSnapshot)
}
}

const useNarrowMediaQuery = makeMediaQueryStore('(max-width: 600px)')

function NarrowScreenNotifier() {
const isNarrow = useNarrowMediaQuery()
return isNarrow ? 'You are on a narrow screen' : 'You are on a wide screen'
}

function App() {
return (
<div>
<div>This is your narrow screen state:</div>
<Suspense fallback="">
<NarrowScreenNotifier />
</Suspense>
</div>
)
}

const rootEl = document.createElement('div')
document.body.append(rootEl)
// 🦉 here's how we pretend we're server-rendering
rootEl.innerHTML = (await import('react-dom/server')).renderToString(<App />)

// 🦉 here's how we simulate a delay in hydrating with client-side js
await new Promise(resolve => setTimeout(resolve, 1000))

ReactDOM.hydrateRoot(rootEl, <App />, {
onRecoverableError(error) {
if (String(error).includes('Missing getServerSnapshot')) return

console.error(error)
},
})

0 comments on commit e06dd63

Please sign in to comment.