Before getting started ๐
Hello.
Across the previous three parts, we explored Next.js 16's performance, architecture, and migration process.
Its real value, however, lies in its
close integration with the latest React, version 19
.
This extra installment introduces new React 19 features available in a Next.js 16 environment.
From
View Transitions
that improve the user experience to
new hooks
for developers, there is plenty to explore.
1. Smooth screen changes with View Transitions ๐
Web apps can feel abrupt or flash when pages change.
React 19 and Next.js 16 support the browser's
View Transitions API
, enabling smooth transitions without a heavy animation library.
React 19's startTransition now supports asynchronous functions, allowing the previous screen to remain visible while data loads before transitioning smoothly to the new screen.
app/components/TabSwitcher.tsx 'use client' ;
import { useTransition, useState } from 'react' ;
import { fetchTabData } from './actions' ;
export default function TabSwitcher () {
const [ isPending , startTransition ] = useTransition ();
const [ data , setData ] = useState ( null );
function handleTabClick ( tabId : string ) {
// [ํต์ฌ] startTransition์ผ๋ก ์ํ ์
๋ฐ์ดํธ๋ฅผ ๊ฐ์๋๋ค.
// React๋ ์ด ์์
์ด ์๋ฃ๋ ๋๊น์ง UI๋ฅผ ์ฐจ๋จํ์ง ์๊ณ ,
// ๋ธ๋ผ์ฐ์ ์ View Transition API์ ์ฐ๋ํ์ฌ ๋ถ๋๋ฌ์ด ์ ํ์ ์ค๋นํฉ๋๋ค.
startTransition ( async () => {
const newData = await fetchTabData (tabId);
setData (newData);
});
}
return (
< div >
< div className = "tabs" >
< button onClick ={ () => handleTabClick ( 'home' ) } >Home</ button >
< button onClick ={ () => handleTabClick ( 'settings' ) } >Settings</ button >
</ div >
{ /* ๋ฐ์ดํฐ ๋ก๋ฉ ์ค์๋ ํฌ๋ช
๋๋ฅผ ์กฐ์ ํ๋ ๋ฑ ์๊ฐ์ ํผ๋๋ฐฑ ์ ๊ณต ๊ฐ๋ฅ */ }
< div style ={ { opacity: isPending ? 0.5 : 1 } } >
{ data ? < Content data ={ data } /> : < p >Select a tab</ p > }
</ div >
</ div >
);
}
2. Stronger Server Actions security ๐
Next.js 16 strengthens security when using
Server Actions
.
When importing server functions into client components, more aggressive
dead code elimination
helps prevent server-only code from entering the client bundle accidentally.
Why does this matter? ๐
It helps prevent accidentally sending database secrets or internal server logic to the client.
The Next.js 16 compiler optimizes calls so the client refers to
only the action's ID
.
app/actions.ts 'use server' ;
// ์ด ํจ์ ๋ด๋ถ์ ๋ก์ง(DB ์ ๊ทผ ๋ฑ)์ ์ ๋ ํด๋ผ์ด์ธํธ๋ก ์ ์ถ๋์ง ์์ต๋๋ค.
export async function submitForm ( formData : FormData ) {
const apiKey = process.env. API_KEY ; // ์๋ฒ ํ๊ฒฝ ๋ณ์
await saveToDb (formData, apiKey);
return { success: true };
}
3. A new hook for UX: useOptimistic ๐
When you send a chat message, its bubble often appears before the server responds.
Implementing this kind of
optimistic update
used to be fairly complicated.
React 19's
useOptimistic makes it much simpler.
app/components/MessageList.tsx 'use client' ;
import { useOptimistic, useRef } from 'react' ;
import { sendMessage } from './actions' ;
export default function MessageList ({ messages } : { messages : string [] }) {
// [ํต์ฌ] useOptimistic ํ
์ฌ์ฉ
// optimsticMessages: ํ๋ฉด์ ๋ณด์ฌ์ค ์์ ์ํ
// addOptimisticMessage: ์์ ์ํ๋ฅผ ์ถ๊ฐํ๋ ํจ์
const [ optimisticMessages , addOptimisticMessage ] = useOptimistic (
messages,
( state , newMessage : string ) => [ ... state, newMessage]
);
async function action ( formData : FormData ) {
const message = formData. get ( 'message' ) as string ;
// 1. ์๋ฒ ์์ฒญ์ ๋ณด๋ด๊ธฐ ์ ์ ํ๋ฉด์ ๋จผ์ ํ์ (๋๊ด์ ์
๋ฐ์ดํธ)
addOptimisticMessage (message);
// 2. ์ค์ ์๋ฒ ์์ฒญ (์คํจ ์ React๊ฐ ์์์ ์ํ๋ฅผ ๋กค๋ฐฑํด ์ค๋๋ค)
await sendMessage (message);
}
return (
< div >
{ optimisticMessages. map (( m , i ) => < div key ={ i } > { m } </ div >) }
< form action ={ action } >
< input name = "message" />
< button type = "submit" >Send</ button >
</ form >
</ div >
);
}
4. useEffectEvent and Activity ๐
Two more React Canary features included in Next.js 16 deserve attention.
Sometimes values inside
useEffect should be
reactive
, while others should not.
For example, you may want to log a connection only when the chat room changes, while still reading the latest theme color.
useEffectEvent lets you read current values without rerunning the effect.
Activity (Offscreen) ๐
Have you ever switched tabs and returned to find your scroll position or input lost?
The
<Activity> component preserves state by hiding an offscreen component, similarly to CSS
display: none, instead of
unmounting
it.
Returning to the screen can therefore reveal its previous state immediately.
This extra installment concludes the Next.js 16 series.
Next.js 16 offers more than speed:
View Transitions
and
new hooks
provide tools for making the web feel smoother and more natural.
Use these techniques appropriately to build experiences that are both fast and thoughtful.
Thank you for following along.