Skip to content

Commit

Permalink
keep working on examples
Browse files Browse the repository at this point in the history
  • Loading branch information
chantastic committed Nov 16, 2024
1 parent 64b97bc commit 308fbaa
Show file tree
Hide file tree
Showing 8 changed files with 599 additions and 182 deletions.
102 changes: 102 additions & 0 deletions chan.dev/src/pages/react19/async_useactionstate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
export const title = "Async Actions"
export const doc = 'https://react.dev/reference/react/useActionState'
export const playground = 'https://stackblitz.com/edit/vitejs-vite-yttb7n?file=src%2FApp.jsx'

export const steps =
[
["Async Actions",
`function StatefulForm() {
const [count, incrementCount] = React.useActionState(
(previousCount) => previousCount + 1,
0
);
return (
<form>
{count}
<button formAction={incrementCount}>Increment</button>
</form>
);
}`],
["Make <code>useActionState</code> callback asynchronous",
`function StatefulForm() {
const [count, incrementCount] = React.useActionState(
async (previousCount) => previousCount + 1,
0
);
return (
<form>
{count}
<button formAction={incrementCount}>Increment</button>
</form>
);
}`], ["Insert some async behavior into Action callback",
`function StatefulForm() {
const [count, incrementCount] = React.useActionState(
async (previousCount) => {
await new Promise((resolve) => setTimeout(resolve, 1000));
return previousCount + 1;
},
0
);
return (
<form>
{count}
<button formAction={incrementCount}>Increment</button>
</form>
);
}`], ["Destructuer <code>isPending</code> from third item in <code>useActionState</code> tuple",
`function StatefulForm() {
const [count, incrementCount, isPending] = React.useActionState(
async (previousCount) => {
await new Promise((resolve) => setTimeout(resolve, 1000));
return previousCount + 1;
},
0
);
return (
<form>
{count}
<button formAction={incrementCount}>Increment</button>
</form>
);
}`], ["Use <code>isPending</code> to show loading state for the form",
`function StatefulForm() {
const [count, incrementCount, isPending] = React.useActionState(
async (previousCount) => {
await new Promise((resolve) => setTimeout(resolve, 1000));
return previousCount + 1;
},
0
);
return (
<form>
{count}
<button formAction={incrementCount}>Increment</button>
{isPending && '🌀'}
</form>
);
}`],
["✅",
`function StatefulForm() {
const [count, incrementCount, isPending] = React.useActionState(
async (previousCount) => {
await new Promise((resolve) => setTimeout(resolve, 1000));
return previousCount + 1;
},
0
);
return(
<form>
{count}
<button formAction={incrementCount}>Increment</button>
{isPending && '🌀'}
</form>
);
}`]
]
66 changes: 44 additions & 22 deletions chan.dev/src/pages/react19/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,62 @@
import MagicMove from './shiki_magic_move'
import Layout from '#layouts/Layout.astro'
import * as prop_types_typescript from './prop_types_typescript'
import * as replace_contexttypes_and_getchildcontext_with_contexttype from './replace_contexttypes_and_getchildcontext_with_contexttype'
import * as replace_string_ref from './replace_string_ref'
import * as remove_module_pattern_factories from './remove_module_pattern_factories'
import * as remove_create_factory from './remove_create_factory'
import * as replace_reacttestrenderershallow_with_reactshallowrenderer from './replace_reacttestrenderershallow_with_reactshallowrenderer'
import * as replace_act_import from './replace_act_import'
import * as replace_reactdom_render from './replace_reactdom_render'
import * as replace_reactdom_hydrate from './replace_reactdom_hydrate'
import * as actions from './actions'
import * as useactionstate from './useactionstate'
import * as async_useactionstate from './async_useactionstate'
import * as use_optimistic from './use_optimistic'
//import * as replace_contexttypes_and_getchildcontext_with_contexttype from './replace_contexttypes_and_getchildcontext_with_contexttype'
//import replace_string_ref from './replace_string_ref'
//import * as remove_module_pattern_factories from './remove_module_pattern_factories'
//import * as remove_create_factory from './remove_create_factory'
//import * as replace_reacttestrenderershallow_with_reactshallowrenderer from './replace_reacttestrenderershallow_with_reactshallowrenderer'
//import * as replace_act_import from './replace_act_import'
//import * as replace_reactdom_render from './replace_reactdom_render'
//import * as replace_reactdom_hydrate from './replace_reactdom_hydrate'
//import * as actions from './actions'
// basic useOptmistic example https://react.dev/reference/react/useOptimistic#usage
// useFormStatus https://react.dev/reference/react-dom/hooks/useFormStatus
// use: https://react.dev/blog/2024/04/25/react-19#new-feature-use
// ref as prop: https://react.dev/blog/2024/04/25/react-19#ref-as-a-prop
// ref cleanup function: https://react.dev/blog/2024/04/25/react-19#cleanup-functions-for-refs
// context as provider: https://react.dev/blog/2024/04/25/react-19#context-as-a-provider
// useDeferredValue (initial value): https://react.dev/blog/2024/04/25/react-19#use-deferred-value-initial-value
// document metadata: https://react.dev/blog/2024/04/25/react-19#support-for-metadata-tags
// - stylesheets (deduped)
// - scripts (async waited)
// - preloading options
function prepExamples(examples) {
return Object.entries(examples).filter(([key]) => key !== "title")
}
---

<Layout>
<Layout style={{backgroundColor: "rgb(26, 27, 38)"}}>
<div class="prose">
{[
prop_types_typescript,
//replace_contexttypes_and_getchildcontext_with_contexttype,
//replace_string_ref,
//remove_module_pattern_factories,
//remove_create_factory,
//replace_reacttestrenderershallow_with_reactshallowrenderer,
//replace_act_import,
//replace_reactdom_render,
//replace_reactdom_hydrate,
//actions,
//useactionstate,
// required refactors
// prop_types_typescript,

// refactors
// useactionstate
// async_useactionstate
use_optimistic,
].map((example) => {
return (
<>
<MagicMove title={example.title ?? "Example"} steps={prepExamples(example)} lang="tsx" client:load />
<MagicMove
title={example.title ?? "Example"}
steps={example.steps}
lang="tsx"
client:load
/>
<div>
<p>
<a href={example.doc} target="_blank">Documentation</a>
<a href={example.playground} target="_blank">Playground</a>
</p>
{example.codemod ? <code>{example.codemod}</code> : null}
</div>
</>
)
})}
Expand Down
76 changes: 51 additions & 25 deletions chan.dev/src/pages/react19/prop_types_typescript.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,55 @@
// https://react.dev/blog/2024/04/25/react-19-upgrade-guide#removed-deprecated-react-apis
// npx codemod@latest react/19/prop-types-typescript

export const title = 'Migrate from PropTypes to TypeScript interface'
export const codemod = 'npx codemod@latest react/19/prop-types-typescript'
export const doc = 'https://react.dev/blog/2024/04/25/react-19-upgrade-guide#removed-deprecated-react-apis'
export const playground = 'https://stackblitz.com/edit/vitejs-vite-vw1vnh?file=src%2FApp.tsx'

export const before =
`import PropTypes from 'prop-types';
export function Heading({ text }) {
return <h1>{text}</h1>;
}
export const steps = [
["Migrate from PropTypes to TypeScirpt interface",
`import PropTypes from 'prop-types';
Heading.propTypes = {
text: PropTypes.string,
};
Heading.defaultProps = {
text: 'Hello, world!',
};`
};
export function Heading({
text
}) {
return <h1>{text}</h1>;
}`],

export const replace_defaultProps_with_destructuring_assignment_default_value =
`import PropTypes from 'prop-types';

["Replace <code>defaultProps</code> with destructuring assignment default value",
`import PropTypes from 'prop-types';
Heading.propTypes = {
text: PropTypes.string,
};
export function Heading({
text = 'Hello, world!'
}) {
return <h1>{text}</h1>;
}`],

["Replace <code>propTypes</code> with TypeScript interface",
`import PropTypes from 'prop-types';
interface Props {
text: string;
}
Heading.propTypes = {
text: PropTypes.string,
};`
export function Heading({
text = 'Hello, world!'
}) {
return <h1>{text}</h1>;
}`],

export const replace_propTypes_with_typescript_interface =
`import PropTypes from 'prop-types';
["Make the <code>text</code> prop optional, because we provide a default value",
`import PropTypes from 'prop-types';
interface Props {
text?: string;
Expand All @@ -43,10 +59,9 @@ export function Heading({
text = 'Hello, world!'
}) {
return <h1>{text}</h1>;
}`

export const apply_typescript_interface_to_props =
`import PropTypes from 'prop-types';
}`],
["Apply TypeScirpt interface to props",
`import PropTypes from 'prop-types';
interface Props {
text?: string;
Expand All @@ -56,16 +71,27 @@ export function Heading({
text = 'Hello, world!'
}: Props) {
return <h1>{text}</h1>;
}`
}`],

export const remove_PropTypes_import =
`interface Props {
["Remove <code>PropTypes</code> import",
`interface Props {
text?: string;
}
export function Heading({
text = 'Hello, world!'
}: Props) {
return <h1>{text}</h1>;
}`],
["✅",
`interface Props {
text?: string;
}
export function Heading({
text = 'Hello, world!'
}: Props) {
return <h1>{text}</h1>;
}`
}`]
]

Loading

0 comments on commit 308fbaa

Please sign in to comment.