Jim Cummins
Network Access Team
https://slides.com/jimthedev/getting-to-know-react-19/fullscreen
Actions!
New hook: useActionState
React DOM: <form> actions, requestFormReset
New React DOM hook: useFormStatus
New hook: useOptimistic
https://slides.com/jimthedev/getting-to-know-react-19/fullscreen
State
https://slides.com/jimthedev/getting-to-know-react-19/fullscreen
const [actionState, submitAction, isPending] = useActionState(
async (previousState, formData) => {
await updateName(String(formData.get("name")));
},
initialValue
);
const [value, setValue] = React.useState(initialValue);
<form action={submitAction}>
<input type="text" name="name" />
<button type="submit" disabled={isPending}>Update</button>
{isPending && <Pending />}
</form>
Action state
https://slides.com/jimthedev/getting-to-know-react-19/fullscreen
import {useFormStatus} from 'react-dom';
function FutureWoodlandButton() {
const { pending, data, method, action } = useFormStatus();
return <button type="submit" disabled={pending} />
}
https://slides.com/jimthedev/getting-to-know-react-19/fullscreen
function ChangeName({currentName, onUpdateName}) {
const [optimisticName, setOptimisticName] = useOptimistic(currentName);
const submitAction = async formData => {
const newName = formData.get("name");
setOptimisticName(newName);
const updatedName = await updateName(newName);
onUpdateName(updatedName);
};
return (
<form action={submitAction}>
<p>Your name is: {optimisticName}</p>
<p>
<label>Change Name:</label>
<input
type="text"
name="name"
disabled={currentName !== optimisticName}
/>
</p>
</form>
);
}
useDeferredValue will have an initial value
Wording change: isLoading is becoming isPending
Context as a provider instead of Context.Provider
ref as a prop, no longer need forwardRef!
Cleanup functions for refs
New (limited use) API: use
https://slides.com/jimthedev/getting-to-know-react-19/fullscreen
https://slides.com/jimthedev/getting-to-know-react-19/fullscreen
const MyInput = React.forwardRef((props, ref) => (
<input placeholder={placeholder} ref={ref} />
));
<MyInput ref={ref} />
function MyInput({placeholder, ref}) {
return <input placeholder={placeholder} ref={ref} />
}
<MyInput ref={ref} />
Forward Ref
Ref as a prop
https://slides.com/jimthedev/getting-to-know-react-19/fullscreen
<input
ref={(ref) => {
// ref created
// NEW: return a cleanup function to reset
// the ref when element is removed from DOM.
return () => {
// ref cleanup
};
}}
/>
Called when component unmounts
https://slides.com/jimthedev/getting-to-know-react-19/fullscreen
import {use} from 'react';
function Comments({commentsPromise}) {
// `use` will suspend until the promise resolves.
const comments = use(commentsPromise);
return comments.map(comment => <p key={comment.id}>{comment}</p>);
}
function Page({commentsPromise}) {
// When `use` suspends in Comments,
// this Suspense boundary will be shown.
return (
<Suspense fallback={<div>Loading...</div>}>
<Comments commentsPromise={commentsPromise} />
</Suspense>
)
}
Probably don't use() this, though
https://slides.com/jimthedev/getting-to-know-react-19/fullscreen
https://slides.com/jimthedev/getting-to-know-react-19/fullscreen
https://slides.com/jimthedev/getting-to-know-react-19/fullscreen
Remove
https://slides.com/jimthedev/getting-to-know-react-19/fullscreen
import {act} from 'react/dom/test-utils'
import {act} from 'react'
react-test-renderer
@testing-library/react
Use
Remove
Use
https://slides.com/jimthedev/getting-to-know-react-19/fullscreen
https://slides.com/jimthedev/getting-to-know-react-19/fullscreen
https://slides.com/jimthedev/getting-to-know-react-19/fullscreen
https://slides.com/jimthedev/getting-to-know-react-19/fullscreen
https://slides.com/jimthedev/getting-to-know-react-19/fullscreen