Client Components

Up until very recently, client components were the only type of components that most developers knew about and used. All popular react tooling, like vite and create-react-app, only worked with client componetns, so we would build Single Page Applications (SPAs) using only client components. That means that all courses and videos that taught react, only taught client components.

Server Components are becoming more popular since Next.js made it so easy to work with them. The default is to use server components, and we now have to opt in to using client components by adding "use client" to the top of every file that we want to use client components in.

Videos

Here are a series of videos that go over some of the core concepts of React using vite. So all examples are for a SPA using only client components by default. You won't see "use client" anywhere because all the components are client components, also all code is in JavaScript instead of Typescript. All the concepts in these videos are still accurate and relevant, especially if you want to setup an SPA, but I have included code examples below each video to demonstrate how these things would work in a modern Next.js app.

To follow along with these videos, you could setup a vite app or just use a next.js app and add "use client" to the top of each file.

Event Handlers

page.tsx
form.tsx
"use client"

import Form from "./form"

export default function Page() {
function handleClick(e: React.MouseEvent<HTMLButtonElement, MouseEvent>) {
console.log("Button clicked")
}

function handleSubmit() {
console.log("Form submitted")
}

return (
<div className="App">
<button onClick={handleClick}>Do Something</button>
<Form onSubmit={handleSubmit} />
</div>
)
}
page.tsx
form.tsx
"use client"

import Form from "./form"

export default function Page() {
function handleClick(e: React.MouseEvent<HTMLButtonElement, MouseEvent>) {
console.log("Button clicked")
}

function handleSubmit() {
console.log("Form submitted")
}

return (
<div className="App">
<button onClick={handleClick}>Do Something</button>
<Form onSubmit={handleSubmit} />
</div>
)
}
page.tsx
form.tsx
"use client"

import Form from "./form"

export default function Page() {
function handleClick(e: React.MouseEvent<HTMLButtonElement, MouseEvent>) {
console.log("Button clicked")
}

function handleSubmit() {
console.log("Form submitted")
}

return (
<div className="App">
<button onClick={handleClick}>Do Something</button>
<Form onSubmit={handleSubmit} />
</div>
)
}
page.tsx
form.tsx
"use client"

import Form from "./form"

export default function Page() {
function handleClick(e: React.MouseEvent<HTMLButtonElement, MouseEvent>) {
console.log("Button clicked")
}

function handleSubmit() {
console.log("Form submitted")
}

return (
<div className="App">
<button onClick={handleClick}>Do Something</button>
<Form onSubmit={handleSubmit} />
</div>
)
}

useState

page.tsx
jokes.tsx
joke.tsx
joke-form.tsx
import Jokes from "./jokes"

export default function Page() {
const jokes = [
{
id: 1,
text: "I'm afraid for the calendar. Its days are numbered.",
},
{
id: 2,
text: "I used to be addicted to soap, but I'm clean now.",
},
]

return (
<div>
<h1>Dad Jokes</h1>
<Jokes jokes={jokes} />
</div>
)
}
page.tsx
jokes.tsx
joke.tsx
joke-form.tsx
import Jokes from "./jokes"

export default function Page() {
const jokes = [
{
id: 1,
text: "I'm afraid for the calendar. Its days are numbered.",
},
{
id: 2,
text: "I used to be addicted to soap, but I'm clean now.",
},
]

return (
<div>
<h1>Dad Jokes</h1>
<Jokes jokes={jokes} />
</div>
)
}
page.tsx
jokes.tsx
joke.tsx
joke-form.tsx
import Jokes from "./jokes"

export default function Page() {
const jokes = [
{
id: 1,
text: "I'm afraid for the calendar. Its days are numbered.",
},
{
id: 2,
text: "I used to be addicted to soap, but I'm clean now.",
},
]

return (
<div>
<h1>Dad Jokes</h1>
<Jokes jokes={jokes} />
</div>
)
}
page.tsx
jokes.tsx
joke.tsx
joke-form.tsx
import Jokes from "./jokes"

export default function Page() {
const jokes = [
{
id: 1,
text: "I'm afraid for the calendar. Its days are numbered.",
},
{
id: 2,
text: "I used to be addicted to soap, but I'm clean now.",
},
]

return (
<div>
<h1>Dad Jokes</h1>
<Jokes jokes={jokes} />
</div>
)
}

React State Array of Objects

page.tsx
jokes.tsx
joke.tsx
joke-form.tsx
import Jokes from "./jokes"

export default function Page() {
const jokes = [
{
id: "1",
text: "I'm afraid for the calendar. Its days are numbered.",
likes: 0
},
{
id: "2",
text: "I used to be addicted to soap, but I'm clean now.",
likes: 0
}
]

return (
<div>
<h1>Dad Jokes</h1>
<Jokes initialJokes={jokes} />
</div>
)
}
page.tsx
jokes.tsx
joke.tsx
joke-form.tsx
import Jokes from "./jokes"

export default function Page() {
const jokes = [
{
id: "1",
text: "I'm afraid for the calendar. Its days are numbered.",
likes: 0
},
{
id: "2",
text: "I used to be addicted to soap, but I'm clean now.",
likes: 0
}
]

return (
<div>
<h1>Dad Jokes</h1>
<Jokes initialJokes={jokes} />
</div>
)
}
page.tsx
jokes.tsx
joke.tsx
joke-form.tsx
import Jokes from "./jokes"

export default function Page() {
const jokes = [
{
id: "1",
text: "I'm afraid for the calendar. Its days are numbered.",
likes: 0
},
{
id: "2",
text: "I used to be addicted to soap, but I'm clean now.",
likes: 0
}
]

return (
<div>
<h1>Dad Jokes</h1>
<Jokes initialJokes={jokes} />
</div>
)
}
page.tsx
jokes.tsx
joke.tsx
joke-form.tsx
import Jokes from "./jokes"

export default function Page() {
const jokes = [
{
id: "1",
text: "I'm afraid for the calendar. Its days are numbered.",
likes: 0
},
{
id: "2",
text: "I used to be addicted to soap, but I'm clean now.",
likes: 0
}
]

return (
<div>
<h1>Dad Jokes</h1>
<Jokes initialJokes={jokes} />
</div>
)
}

useEffect

Components must be pure

In React, components are functions that take input data and return output markup. It's important to keep the component function focused on rendering and not interacting with external systems like network requests or updating the window object. Any interaction with external systems is considered a side effect.

if (images.length === 0) {
return 'No memes'
}
if (images.length === 0) {
return 'No memes'
}
if (images.length === 0) {
return 'No memes'
}
if (images.length === 0) {
return 'No memes'
}

This code inside of a components is absolutely fine because the logic here is only accessing state that exists within the component, and only returning markup that will be rendered to the dom. There is no interaction with an external system.

But what about this code:

// Bad because it's in the top level of the component and is executed as part of the component rendering
document.title = `You have ${images.length} memes`
// Bad because it's in the top level of the component and is executed as part of the component rendering
document.title = `You have ${images.length} memes`
// Bad because it's in the top level of the component and is executed as part of the component rendering
document.title = `You have ${images.length} memes`
// Bad because it's in the top level of the component and is executed as part of the component rendering
document.title = `You have ${images.length} memes`

This code interacts with an external system, the document, and is considered a side effect. To avoid running side effect code in the component function, we can create a function that causes side effects and call it later, such as when a user clicks a button.

// Good because it's inside a function that isn't executed as part of the component rendering
const updateDocumentTitle = () => {
document.title = `You have ${images.length} memes`
}

return (
// ...
<button onClick={updateDocumentTitle}>
// Good because it's inside a function that isn't executed as part of the component rendering
const updateDocumentTitle = () => {
document.title = `You have ${images.length} memes`
}

return (
// ...
<button onClick={updateDocumentTitle}>
// Good because it's inside a function that isn't executed as part of the component rendering
const updateDocumentTitle = () => {
document.title = `You have ${images.length} memes`
}

return (
// ...
<button onClick={updateDocumentTitle}>
// Good because it's inside a function that isn't executed as part of the component rendering
const updateDocumentTitle = () => {
document.title = `You have ${images.length} memes`
}

return (
// ...
<button onClick={updateDocumentTitle}>

Event listeners, like onClick or onSubmit, are a great place to run side effects because they are triggered by user interaction and not part of the component rendering. And this is usually where you want to start with side effects. Add an event listener.

But if I refresh the page, we can see that the window's title isn't right, it should say 0 memes, or if I had some initial data in the images array, then it should say however many images i have. Basically, I don't want this side effect to be triggered by an user event. I want this side effect to be triggered by a state update.

useEffect for Side Effects

I want this side effect to be in sync with the state of my component. And this is where the useEffect hook comes in.

We use useEffect by importing it, then calling it inside of the component function. And we pass it a function and run any side effect code. And now everything just works, like magic. React will run the useEffect function after the component is rendered.

useEffect(() => {
document.title = `You have ${images.length} memes`
})
useEffect(() => {
document.title = `You have ${images.length} memes`
})
useEffect(() => {
document.title = `You have ${images.length} memes`
})
useEffect(() => {
document.title = `You have ${images.length} memes`
})

useEffect will let you run some code after rendering so that you can synchronize your component with some system outside of React.

So that's the basic idea of useEffect. It's a hook that lets you run some code after the component is rendered to synchronize your component and it's state with some system outside of React. Rendering the UI is driven by props and state, and is guaranteed to be consistent with them, but side effects are not. useEffect is for side effects, not for rendering the UI. It's important to keep that in mind.

More React Content

If you want to learn more about using React for client side SPAs, then check out my full playlist on React: https://www.sammeechward.com/playlists/all-you-need-to-know-about-react-js