Week 10

Refs

Custom hooks

React 19

React Server Components

Practice

Assignment

Front end Track

Content

Let’s get practical

Exercise 1: Focus Management with Refs

Difficulty: Easy Concepts: useRef, DOM manipulation, focus management, accessibility

Build a comment form that manages focus automatically as the user interacts with it.

Requirements:

Requirements for refs:

Hints:

Exercise 2: Refactor a Client Component to a Server Component

Difficulty: Medium Concepts: React Server Components, async components, Next.js App Router, Server Functions

You have a bloated Client Component that fetches a list of blog posts using useEffect. Refactor it into a Server Component and wire up a Server Function to handle marking a post as read.

Starting point:

'use client';

import { useState, useEffect } from 'react';

interface Post {
  id: number;
  title: string;
  body: string;
  userId: number;
}

export default function PostList() {
  const [posts, setPosts] = useState<Post[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    const controller = new AbortController();

    fetch('<https://jsonplaceholder.typicode.com/posts?_limit=10>', {
      signal: controller.signal,
    })
      .then((res) => {
        if (!res.ok) throw new Error(`HTTP ${res.status}`);
        return res.json();
      })
      .then((data) => {
        setPosts(data);
        setLoading(false);
      })
      .catch((err) => {
        if (err.name !== 'AbortError') {
          setError(err.message);
          setLoading(false);
        }
      });

    return () => controller.abort();
  }, []);

  if (loading) return <p>Loading posts...</p>;
  if (error) return <p>Error: {error}</p>;

  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>
          <h2>{post.title}</h2>
          <p>{post.body}</p>
        </li>
      ))}
    </ul>
  );
}

Part 1 — Refactor to a Server Component:

Part 2 — Add a Server Function:

The final file structure should look like this:

app/
└── posts/
    ├── page.tsx              ← async Server Component
    ├── MarkAsReadButton.tsx  ← Client Component ('use client')
    └── actions.ts            ← Server Function ('use server')

Hints:


The HackYourFuture curriculum is licensed under CC BY-NC-SA 4.0 *https://hackyourfuture.net/*

CC BY-NC-SA 4.0 Icons

Built with ❤️ by the HackYourFuture community · Thank you, contributors

Found a mistake or have a suggestion? Let us know in the feedback form.