원클릭으로
latest-nextjs
Latest React and Next.js features for past 1.5 years (mid-2024 to 2026)
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Latest React and Next.js features for past 1.5 years (mid-2024 to 2026)
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
| name | latest-nextjs |
| description | Latest React and Next.js features for past 1.5 years (mid-2024 to 2026) |
| updated | "2026-01-11T00:00:00.000Z" |
Comprehensive knowledge of React and Next.js features from mid-2024 through 2025. This skill fills the gap between LLM training cutoffs and current knowledge, covering React 19.2 (October 2025), Next.js 16 (October 2025), and supporting ecosystem changes.
useOptimisticManages optimistic UI updates during async mutations:
import { useOptimistic } from "react";
function LikeButton({ postId, initialLiked }) {
const [optimisticLiked, addOptimistic] = useOptimistic(
initialLiked,
(state, newLiked) => !state
);
async function handleToggle() {
addOptimistic(!optimisticLiked);
await toggleLike(postId);
}
return (
<button onClick={handleToggle}>
{optimisticLiked ? "Unlike" : "Like"}
</button>
);
}
Use cases: Like buttons, todo lists, any UI showing predicted state during server updates.
useActionStateConnects forms to action functions and tracks response state:
import { useActionState } from "react";
const [state, formAction, isPending] = useActionState(
async (prevState, formData) => {
const email = formData.get("email");
await subscribe(email);
return { success: true, message: "Subscribed!" };
},
null
);
Replaces: Manual form state management, loading states, error handling.
useFormStatusAccesses parent form status from nested components:
import { useFormStatus } from "react";
function SubmitButton() {
const { pending, data, method, action } = useFormStatus();
return (
<button disabled={pending}>{pending ? "Sending..." : "Submit"}</button>
);
}
Key use case: Submit buttons that need parent form state.
useTransitionNow supports async functions with automatic state management:
const [isPending, startTransition] = useTransition();
startTransition(async () => {
// Automatic pending, error, and optimistic UI handling
await searchAPI(query);
});
use HookReads resources (Promises, Context) in render:
import { use } from "react";
// Read promises in Server Components
const data = use(fetchPromise);
// Read context
const theme = use(ThemeContext);
Use case: Streaming data in Server Components without useEffect.
Production-ready and used at scale by Meta (Facebook, Instagram):
// Server Component - runs on server only
async function BlogPost({ id }) {
const post = await db.post.findUnique({ where: { id } });
return <article>{post.content}</article>;
}
Key characteristics:
Automatically optimizes components without manual memoization:
Before:
const memoizedValue = useMemo(() => expensiveCalc(a, b), [a, b]);
const memoizedCallback = useCallback(() => doSomething(a, b), [a, b]);
With Compiler:
// Compiler automatically optimizes
const value = expensiveCalc(a, b);
const callback = () => doSomething(a, b);
Capabilities:
Simplified server-side mutations:
// app/actions.ts
"use server";
export async function updateProfile(formData: FormData) {
const name = formData.get("name");
await db.user.update({ where: { id }, data: { name } });
}
// Client Component usage
import { updateProfile } from "./actions";
export default function ProfileForm() {
return (
<form action={updateProfile}>
<input name="name" />
<button type="submit">Update</button>
</form>
);
}
React 19 eliminates much of the complexity:
// No more controlled state needed
export default function ContactForm() {
return (
<form
action={async (formData) => {
await submitToServer(formData);
}}
>
<input name="email" />
<button type="submit">Submit</button>
</form>
);
}
.Provider// Before
<MyContext.Provider value={value}>{children}</MyContext.Provider>
// React 19+
<MyContext value={value}>{children}</MyContext>
forwardRef// Before
const Button = forwardRef((props, ref) => <button ref={ref} {...props} />);
// React 19+
const Button = ({ ref, ...props }) => <button ref={ref} {...props} />;
Place <title>, <meta>, <link> directly in components:
function BlogPost({ title, description }) {
return (
<>
<title>{title} | My Blog</title>
<meta name="description" content={description} />
<meta property="og:title" content={title} />
<article>{content}</article>
</>
);
}
React automatically "hoists" these to <head>.
Ref callbacks can now return cleanup functions:
const buttonRef = useCallback((element: HTMLButtonElement | null) => {
if (!element) return; // cleanup on unmount
const handler = () => console.log("Clicked");
element.addEventListener("click", handler);
return () => element.removeEventListener("click", handler);
}, []);
createRoot(document.getElementById("root")!, {
onCaughtError: (error, errorInfo) => {
// Errors caught by Error Boundaries
console.error("Caught:", error, errorInfo);
},
onUncaughtError: (error, errorInfo) => {
// Errors NOT caught by Error Boundaries
console.error("Uncaught:", error, errorInfo);
},
});
Full support for Web Components with proper attribute and event handling.
Turbopack is now the default bundler for both next dev and next build:
# Turbopack is now default - no flags needed
next dev
next build
Performance improvements:
Cache Components replace Partial Prerendering (PPR) with a more explicit caching model:
// next.config.js - Enable Cache Components
export default {
cacheComponents: true, // Opt-in feature
};
Key characteristics:
proxy.ts Replaces middleware.tsMiddleware has been renamed to proxy:
// Before: middleware.ts
export function middleware(request: NextRequest) {
// logic
}
// After: proxy.ts
export function proxy(request: NextRequest) {
// Same logic, just renamed
}
Migration:
# Automated codemod available
npx @next/codemod@canary middleware-to-proxy
What changed:
middleware.ts → proxy.tsmiddleware → proxyRoute parameters are now async:
// Before Next.js 16
export default async function Page({ params, searchParams }) {
const id = params.id;
const query = searchParams.q;
}
// Next.js 16+
export default async function Page({ params, searchParams }) {
const id = await params.id; // Now async!
const query = await searchParams.q; // Now async!
}
This is a breaking change requiring migration of components using params/searchParams.
Full compatibility and optimization for React 19.2 features.
unstable_ APIs promoted to stableFile-system based router with Server Components:
app/
layout.tsx # Root layout
page.tsx # Home page
blog/
layout.tsx # Blog section layout
[slug]/ # Dynamic route
page.tsx # Blog post page
Direct server-side mutations from client components:
// app/actions.ts
"use server";
export async function createTodo(formData: FormData) {
const title = formData.get("title");
await db.todo.create({ data: { title } });
}
// app/page.tsx
import { createTodo } from "./actions";
export default function Page() {
return (
<form action={createTodo}>
<input name="title" />
<button type="submit">Add</button>
</form>
);
}
All components in app/ are Server Components by default:
// Server Component - no 'use client' needed
async function Dashboard() {
const user = await getCurrentUser();
const posts = await db.post.findMany();
return <div>Welcome {user.name}</div>;
}
Add 'use client' directive only for:
onClick, etc.)useState, useEffect, etc.)More predictable and granular caching:
revalidatePath/revalidateTagfetch requests cached by default// Cache for 1 hour
const data = await fetch("https://api.example.com/data", {
next: { revalidate: 3600 },
});
// Invalidate on demand
revalidatePath("/blog");
revalidateTag("posts");
after() APIPost-response operations:
import { after } from "next/server";
export default function handler() {
after(() => {
// Runs after response is sent to client
analytics.track();
});
return <Response />;
}
// Server Action
"use server";
async function submitContact(prevState, formData) {
const email = formData.get("email");
await db.contact.create({ data: { email } });
return { success: true };
}
// Client Component
("use client");
import { useActionState } from "react";
import { submitContact } from "./actions";
export default function ContactForm() {
const [state, formAction, isPending] = useActionState(submitForm, null);
return (
<form action={formAction}>
<input name="email" disabled={isPending} />
<button disabled={isPending}>
{isPending ? "Sending..." : "Submit"}
</button>
{state?.success && <p>Thanks!</p>}
</form>
);
}
"use client";
import { useOptimistic } from "react";
import { toggleLike } from "./actions";
function LikeButton({ postId, initialLiked }) {
const [optimisticLiked, addOptimistic] = useOptimistic(
initialLiked,
(state) => !state
);
return (
<button
formAction={async () => {
addOptimistic();
await toggleLike(postId);
}}
>
{optimisticLiked ? "Unlike" : "Like"}
</button>
);
}
// Simple, direct database access
async function BlogList() {
const posts = await db.post.findMany({
orderBy: { createdAt: "desc" },
});
return (
<div>
{posts.map((post) => (
<article key={post.id}>
<h2>{post.title}</h2>
<p>{post.excerpt}</p>
</article>
))}
</div>
);
}
import { Suspense } from "react";
export default function Dashboard() {
return (
<div>
<h1>Dashboard</h1>
<Suspense fallback={<StatsSkeleton />}>
<Stats />
</Suspense>
<Suspense fallback={<PostsSkeleton />}>
<RecentPosts />
</Suspense>
</div>
);
}
Update async params:
// Add await to all params/searchParams access
const id = await params.id;
Rename middleware to proxy:
npx @next/codemod@canary middleware-to-proxy
Enable Turbopack (already default, but verify):
next dev --turbo # Should be default now
Consider Cache Components:
// next.config.js
export default {
cacheComponents: true, // Opt-in for new caching model
};
forwardRef, update Context syntaxcreateRoot| Pages Router | App Router |
|---|---|
pages/index.js | app/page.tsx |
getServerSideProps | async Server Component |
getStaticProps | async Server Component + generateStaticParams |
getStaticPaths | generateStaticParams |
_app.js | app/layout.tsx |
_document.js | app/layout.tsx |
API routes pages/api/ | Route handlers app/api/ |
// app/blog/[slug]/page.tsx
export async function generateMetadata({ params }) {
const post = await getPost(params.slug);
return {
title: post.title,
description: post.excerpt,
openGraph: {
title: post.title,
images: [post.ogImage],
},
};
}
// app/blog/loading.tsx
export default function Loading() {
return <BlogListSkeleton />;
}
// Or inline Suspense
export default function BlogPage() {
return (
<Suspense fallback={<BlogListSkeleton />}>
<BlogList />
</Suspense>
);
}
// app/blog/error.tsx
"use client";
export default function Error({ error, reset }) {
return (
<div>
<h2>Something went wrong!</h2>
<button onClick={() => reset()}>Try again</button>
</div>
);
}
Initial Convex workspace setup in Coder workspaces with self-hosted Convex deployment, authentication configuration, Docker setup, and environment variable generation
Self-hosted Convex development in Coder workspaces with authentication, queries, mutations, React integration, and environment configuration
Guides self-hosted Convex deployment, authentication setup, environment configuration, troubleshooting, and production deployment considerations.
Coder workspace environment for hahomelabs.com deployments. Includes networking, ports, convex config, nhost config
Manages git operations including commits, pull requests, merge requests, and branching. Use when creating commits, handling git conflicts, managing branches, or reviewing git history. Enforces clean commit messages without author attribution.
Refactors Claude Code skills to reduce token usage 80-95% using Progressive Disclosure Architecture (PDA). Splits monolithic skills into orchestrator + reference files, extracts scripts, creates reference/ directories. Use when optimizing skills, improving skill efficiency, refactoring large/bloated skills, reducing token costs, applying PDA, modularizing skills, breaking down skills, or converting encyclopedia-style skills to orchestrator pattern.