Next.js after React: what actually changes
See what changes after React: which file is a page, when a component needs the browser, and why a notes list can skip useEffect.

What actually changes when you open a Next.js project after learning React, and do you still load data with useEffect?
Short answer: React still renders the UI. Next.js adds the pages, runs components on the server by default, and lets a page wait for data before it sends HTML. You still write React. The new question is where that React runs.
By the end of this post you will know which file becomes a URL, when a button has to opt into the browser, and why a notes list can skip useEffect. New to components? Start with Your First Component (opens in a new tab), then come back.
A page is still a component
In the App Router, a page is a React component with a default export. The folder is the URL, and the file has to be named page, which is page.tsx in these examples. Next.js Fundamentals (opens in a new tab) is built on that setup.
export default function Page() {
return <h1>Notes</h1>
}Put that in app/page.tsx and it is the home page, /. The same kind of component in app/notes/page.tsx is /notes. A folder with no page.tsx isn't a page you can visit, which is why app/notes/NoteButton.tsx can sit beside the page without becoming its own URL. You can name the function whatever you like. What matters is the default export, in a file named page.tsx.
That first change is smaller than the new files make it look. In a plain React app you usually configure a router and keep a list of paths. Here you create a folder and drop in page.tsx, and the path exists because the folder exists. The File Based Routing (opens in a new tab) lesson is the full map.
Most of the page runs on the server
In a plain React app, your components run in the browser. Here, a component is a Server Component unless you say otherwise. The server renders it to HTML and sends that HTML down, so that component's code doesn't ship to the browser at all. That is useful for a notes page that only needs to show titles. It is the wrong place for a button that updates a count, because useState, useEffect, and onClick need the browser.
Those go in a Client Component. The opt-in is a string on the first line of the file, before the imports:
"use client"
import { useState } from "react"
export default function NoteButton() {
const [saved, setSaved] = useState(false)
return (
<button onClick={() => setSaved(true)}>{saved ? "Saved" : "Save"}</button>
)
}The server page can render that button and pass it data as props. The button can't import a Server Component and expect it to run on the server, which is why the interactive piece should stay small. Leave the directive out and Next.js throws an error as soon as that file uses useState, useEffect, or onClick. The fix is the line at the top of the button's file, not a "use client" on the whole notes page. State inside the button is the same React you already know, and useState or useReducer still applies there.
The fetch moves out of useEffect
This is the part that trips people who learned data loading in React. The URL below is a placeholder, not a live notes API.
The React version renders once with no notes, then loads them in the browser:
"use client"
import { useEffect, useState } from "react"
export default function Notes() {
const [notes, setNotes] = useState<{ id: string; title: string }[]>([])
useEffect(() => {
fetch("https://example.com/api/notes")
.then((res) => res.json())
.then(setNotes)
}, [])
return (
<ul>
{notes.map((note) => (
<li key={note.id}>{note.title}</li>
))}
</ul>
)
}The page is on screen before the notes are, which is why this pattern so often needs a loading state. The useEffect guide is the plain-React version of that idea.
A Server Component can be async and wait for the data before it sends HTML:
export default async function Notes() {
// The server waits here, so the HTML already includes the notes.
const res = await fetch("https://example.com/api/notes")
const notes = await res.json()
return (
<ul>
{notes.map((note) => (
<li key={note.id}>{note.title}</li>
))}
</ul>
)
}Because the server waits for the data, there is no useEffect and no empty first render to fill in later. Here is the order for one visit to /notes. The server runs Notes, waits for fetch, and only then builds the HTML, with the titles already inside the list. The browser paints that HTML. There is no second trip where React fills an empty list, which is the trip the useEffect version was making, and the reason that version needs a loading state this one can skip.
The request runs on the server, so a token used in that fetch doesn't have to ship to the browser. The Data Fetching In Next.js (opens in a new tab) lesson is this comparison.
That await only works in a Server Component. If the file has "use client" because it needs a click or state, it is back to useEffect for its own fetch. Load the notes on the server and pass them down as props. The page keeps the request, and the button keeps the click.
Which kind of component is this?
| Plain React | Server Component | Client Component | |
|---|---|---|---|
| Where it runs | In the browser | On the server, by default | In the browser, after you opt in |
useState and onClick | Yes | No | Yes |
| How a notes list gets its data | Usually useEffect after the first render | await fetch before the HTML is sent | useEffect, if this file owns the fetch |
| When it fits | A React app you wire up yourself | Pages, layouts, and data | A button, a filter, a field |
Common mistakes
- Adding
useStateto a file that is still a Server Component. Next.js throws an error because that hook needs the browser. Move the button into its own file and mark that file"use client". - Marking the whole notes page as a client component to silence the error. That ships more of the page to the browser and pulls the fetch back into
useEffect. Keep the page on the server and opt in only the button. - Treating every file in
app/as a route. Only apagefile (page.tsxhere) makes a page you can visit.app/notes/NoteButton.tsxis a component.app/notes/page.tsxis the page. - Importing a Server Component into a client file and expecting the server to run it. The arrow goes one way. The server page renders the client button, not the other way around.
What you can leave alone
Components, props, and JSX don't change. A list still needs a key. A client button still uses useState the way you learned it in React Fundamentals. The page files use the .tsx extension. The one type annotation above, on the useState in the client notes list, tells TypeScript what a note looks like. The rest reads as the React you already know. The file tree is the new part. The component model isn't.
Quick recap
- A page is a React component in
page.tsx. The folder is the URL. - Components run on the server unless the file starts with
"use client". useState,useEffect, andonClickbelong in the client file, and that file should stay small.- A Server Component can
await fetchand send HTML that already includes the notes. - Props, JSX, and
keystill work the way you learned them.
Frequently asked questions
Is Next.js a replacement for React?
It isn't a replacement. React still renders the components, and Next.js is the framework around that, adding routing, server rendering, and a place to load data. The Next.js Fundamentals (opens in a new tab) course assumes you have finished React Fundamentals (opens in a new tab), or that you are already comfortable building React apps.
Do I still need useEffect in Next.js?
Often you don't, for data the page can load on the server. You still need it, or another client hook, when the fetch belongs to a component that has to run in the browser. The notes list in this post is the first case.
What is the App Router?
It is the routing setup where a folder inside app/ is a URL and page.tsx is the page. You don't keep a separate list of routes. That is the setup the Next.js course uses.
What is the difference between a Server Component and a Client Component?
A Server Component runs on the server and is the default. A Client Component opts into the browser with "use client" so it can use state and clicks. A server page can render a client button. A client file can't pull a Server Component back onto the server.
Do I need to know React before Next.js?
This course expects React first. You want to be comfortable building a component, passing props, and keeping state, which is what React Fundamentals (opens in a new tab) covers. Next.js assumes those pieces.
Practice
The matching exercises are in the course. Create the page in Your First Page (opens in a new tab), make the server-and-client split in Server Vs Client Components (opens in a new tab), and load data in Your First Server Fetch (opens in a new tab). Each exercise works in your browser, so there is nothing to install.
Later in that course you build a small coffee shop, Roastery, with this same split.
Keep going
Open the course that matches where you are. If components are rusty, React Fundamentals (opens in a new tab) is the right first click. Brad Traversy (opens in a new tab) teaches Next.js Fundamentals (opens in a new tab), which is where the notes-page ideas become a project you run.







