Created
September 2, 2022 20:03
-
-
Save wycats/96141ba6055f20d6695d3aebda97b678 to your computer and use it in GitHub Desktop.
An explanation of how Starbeam integrates with React 18's reusable state (https://github.com/reactwg/react-18/discussions/19)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Cell } from "@starbeam/core"; | |
import { useSetup } from "@starbeam/react"; | |
const SYSTEM_LOCALE = Intl.DateTimeFormat().resolvedOptions().locale; | |
const SYSTEM_TZ = Intl.DateTimeFormat().resolvedOptions().timeZone; | |
function Clock({ locale = SYSTEM_LOCALE, timeZone = SYSTEM_TZ }) { | |
const now = useSetup((component) => { | |
const now = Cell(new Date())); | |
// This is basically useEffect. | |
component.on.idle(() => { | |
const interval = | |
setInterval(() => now.set(new Date()), 1000); | |
return () => clearInterval(now); | |
}); | |
return now; | |
}); | |
function format() { | |
return new Intl.DateTimeFormat(locale, { | |
hour: "numeric", | |
minute: "numeric", | |
second: "numeric", | |
timeZoneName: "long", | |
timeZone, | |
}) | |
.format(now.current); | |
} | |
return <p className="output">{format()}</p> | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Cell } from "@starbeam/core"; | |
import { useSetup } from "@starbeam/react"; | |
const SYSTEM_LOCALE = Intl.DateTimeFormat().resolvedOptions().locale; | |
const SYSTEM_TZ = Intl.DateTimeFormat().resolvedOptions().timeZone; | |
function Clock({ locale = SYSTEM_LOCALE, timeZone = SYSTEM_TZ }) { | |
// useSetup runs when the component is mounted, and again when the | |
// component is remounted (i.e. when React runs useEffect and | |
// useLayoutEffect setup functions when the dependencies haven't | |
// changed, https://github.com/reactwg/react-18/discussions/19). | |
// | |
// In general, you can think of this as an "onMount"-style hook. | |
// But: you can ergonomically use it to set up state in your render | |
// function that is used in your JSX and managed in an effect, since | |
// you'll get a fresh copy of the setup state every time React | |
// remounts the component. | |
const now = useSetup((component) => { | |
// This state will be available on the first render, and will be | |
// updated in the effect below. This is a critical aspect of what | |
// we need here: | |
// | |
// - A value that we can use right away during initial render | |
// - To defer the stateful setup code until useEffect timing, because | |
// otherwise we're not guaranteed that the cleanup code will run | |
const now = Cell(new Date())); | |
// This is basically useEffect. When React unmounts this component, | |
// the cleanup function (of course) gets called. When React | |
// *re-mounts* this component, the whole setup function gets invoked | |
// again, creating a fresh `now` for the effect to work with. | |
component.on.idle(() => { | |
const interval = | |
setInterval(() => now.set(new Date()), 1000); | |
return () => clearInterval(now); | |
}); | |
return now; | |
}); | |
// This is a normal function. It gets created on every render, which | |
// means that whenever React runs the render function, you get a new | |
// copy of the `format` function that closes over the correct `locale` | |
// and `timeZone`. | |
function format() { | |
return new Intl.DateTimeFormat(locale, { | |
hour: "numeric", | |
minute: "numeric", | |
second: "numeric", | |
timeZoneName: "long", | |
timeZone, | |
}) | |
// this function can refer to the `now` cell, | |
// which is a stable value that will be updated | |
// below. | |
.format(now.current); | |
} | |
return <p className="output">{format()}</p> | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment