Actions Directives Compiler New Hooks
React 19
use() hook Less Code Optimistic Better Perf
Install React 19
ReactBootcamp.dev
React Compiler
- compiler increases performance
- removes need to write certain hooks
- reduces code you need to write
converts to…
ReactBootcamp.dev
No More Memoization
const [count, setCount] = useState(0)
new React compiler
removes the need to use:
const increment = () => setCount((c) => c + 1)
const doubleCount = count * 2
return (
<>
<div>Count: {count}</div>
<div>Double Count: {doubleCount}</div>
<Button increment={increment} />
</>
)
ReactBootcamp.dev
No More forwardRef
import { forwardRef } from 'react'
const MyInput = forwardRef(function MyInput(props, ref) {
// ...
});
ReactBootcamp.dev
Without forwardRef
function App() {
const buttonRef = useRef()
const onButtonClick = () => console.log(buttonRef.current)
return (
<Button ref={buttonRef} onClick={onButtonClick}>
Click Me
</Button>
)
} access ref like any other prop
const Button = ({ ref, ...props }) => {
return <button ref={ref} {...props} />
}
ReactBootcamp.dev
use() hook
!
promises
lets you load resources asynchronously
context
use() replaces
multi-purpose hook
useEffect() useContext()
for data fetching for reading context
ReactBootcamp.dev
Fetch data - use()
function Person() {
const person = use(fetchPerson()) 1. resolve with use()
return <h1>{person.name}</h1>
}
3. display data in UI
function App() {
return (
<Suspense fallback={<h1>Loading...</h1>}> 2. show fallback
<Person />
</Suspense>
)
}
async function fetchPerson() {
const response = await fetch("https://swapi.dev/api/people/1")
return response.json()
} ReactBootcamp.dev
Read context - use()
const UserContext = createContext("")
function User() {
const user = use(UserContext) replace useContext with use()
return <h1>Hello, {user}!</h1>
}
function App() {
return (
<UserContext.Provider value="Dave">
<User />
</UserContext.Provider>
)
}
ReactBootcamp.dev
Directives
commands to run React "use client" add to top of component
code on server or client
used already
in Next.js big, but simple
“use client” “use server”
ReactBootcamp.dev
Actions
make forms much easier function connected to form
function myAction(formData) {}
<form action={formAction}>
Can be run on server or client
ReactBootcamp.dev
Client Actions
"use client"
1. mark as client component
function App() {
function formAction(formData) { 3. get input value from formData
alert("You typed: " + formData.get("name"))
}
return (
<form action={formAction}> 2. connect function to action prop
<input type="text" name="name" />
<button type="submit">Submit</button>
</form>
)
}
ReactBootcamp.dev
useFormStatus()
it will usually take time
for actions to complete
import { useFormStatus } from "react-dom"
disable submit
while pending
submission is pending Loading…
ReactBootcamp.dev
useFormStatus()
function Submit() {
const { pending } = useFormStatus() 2. get pending from hook
return <button disabled={pending}>Submit</button>
}
3. pass pending to disabled prop
function App() {
async function formAction(formData) {/*...*/}
return (
<form action={formAction}>
<input name="name" />
<Submit /> 1. nest component inside form
</form>
)
}
ReactBootcamp.dev
useFormState()
What if you want the data
returned from your action?
Stateful hook
import { useFormState } from "react-dom"
ReactBootcamp.dev
Basic - useFormState()
Preview
async function increment(previousState, formData) {
return previousState + 1
}
function StatefulForm() { 0
const [state, formAction] = useFormState(increment, 0)
Days without a new
return ( framework
<form>
{state} Increment
<button formAction={formAction}>Increment</button>
</form>
)
}
ReactBootcamp.dev
Basic - useFormState()
async function increment(previousState, formData) { 2. it gets prev state + formData
return previousState + 1
}
function StatefulForm() {
const [state, formAction] = useFormState(increment, 0) 1. hook takes action + initial value
return (
<form>
{state}
3. use returned state from action
<button formAction={formAction}>Increment</button>
</form>
)
}
ReactBootcamp.dev
Cart - useFormState()
Added to cart!
ReactBootcamp.dev
Cart - useFormState()
function addToCart(prevState, formData) {
const productId = formData.get("productId")
return productId === "1" ? "Added to cart!" : "Out of stock"
}
function App() {
const [message, formAction] = useFormState(addToCart, null) 1. call addToCart action
return (
<form action={formAction}>
<h2>My Product</h2>
<input type="hidden" name="productId" value="1" />
<button>Submit</button>
{message && <p>{message}</p>}
</form>
)
} ReactBootcamp.dev
Cart - useFormState()
function addToCart(prevState, formData) {
const productId = formData.get("productId")
return productId === "1" ? "Added to cart!" : "Out of stock" 3. return message
}
function App() {
const [message, formAction] = useFormState(addToCart, null) 1. call addToCart action
return (
<form action={formAction}>
<h2>My Product</h2>
<input type="hidden" name="productId" value="1" /> 2. pass productId (“1”) via input
<button>Submit</button>
{message && <p>{message}</p>} 4. display in UI
</form>
)
} ReactBootcamp.dev
useOptimistic()
What to do while we’re waiting
for action to finish running?
optimistic update
Ideal for const [optimisticState, addOptimistic] = useOptimistic(
real-time apps state,
// updateFn
(currentState, optimisticValue) => {
// merge and return new state
// with optimistic value
}
)
ReactBootcamp.dev
Chat - useOptimistic()
yeah lol
ReactBootcamp.dev
Chat - useOptimistic()
yeah lol (sending…)
ReactBootcamp.dev
Chat - useOptimistic()
yeah lol
delivered
ReactBootcamp.dev
Chat - useOptimistic()
function ChatApp() {
const [messages, setMessages] = useState([]) 1. store messages in state
const [optimisticMessages, addOptimisticMessage] = useOptimistic( 2. pass messages to hook
messages,
(state, newMessage) => [...state, { text: newMessage, sending: true }] 4. perform temp update
);
async function formAction(formData) {
const message = formData.get("message");
addOptimisticMessage(message); 3. add optimistic message
const createdMessage = await createMessage(message);
setMessages((messages) => [...messages, { text: createdMessage }]); 5. replace w/ saved message
}
//…
}
ReactBootcamp.dev