How do I make Next.js 13 server-side components in the app directory that depend on useEffect for props?

I’m trying to write a Next.js 13 newsletter page in the app directory that uses server-side components that depend on useEffect for props. The useEffect fetches data from a REST API to get newsletters which will render the content of the page. The code I’m using is below. I’m having trouble figuring out how to configure the server-side components to work when I need to "use client" for interactivity. How can I make sure that the server-side components are rendered before it is sent to the client?

Code:

import Navbar from '@/components/navbar'
import Footer from '@/components/footer'
import Pagination from './pagination'
import IssueCards from './issueCards';
import { useState, useEffect } from 'react';
import axios from 'axios';


const Newsletters = () => {
    const [issues, setIssues] = useState([]);
    const [currentPage, setCurrentPage] = useState(1);
    const [issuesPerPage, setIssuesPerPage] = useState(5);

    useEffect(() => {
        const fetchIssue = async () => {
            const res = await axios.get(`${process.env.NEXT_PUBLIC_BACKEND_API}/newsletters`)
            setIssues(res.data)
        }
        fetchIssue()
    }, [])
    
    // Change page
    const paginate = (pageNumber) => setCurrentPage(pageNumber);

    const indexOfLastIssue = currentPage * issuesPerPage;
    const indexOfFirstIssue = indexOfLastIssue - issuesPerPage;
    const currentIssues = issues.slice(indexOfFirstIssue, indexOfLastIssue)

    return (
        <>
            <Navbar />
            <div className="newsletter-container" id='newsletter-container'>
                <h1>Newsletters</h1>
                <hr></hr>
                <div className="newsletter-wrapper">
                    <IssueCards issues={currentIssues} />
                    <Pagination 
                        issuesPerPage={issuesPerPage} 
                        totalIssues={issues.length} 
                        paginate={paginate} 
                    />
                </div>
            </div>
            <Footer />
        </>
    );
}

export default Newsletters;

How do I configure Next.js 13 server-side components that depend on useEffect for props and ensure that the content is rendered before it is sent to the client?

I tried following the Nextjs docs on Server and Client components but I am unsure of how I can pass down the props information onto the server.

>Solution :

Unfortunately, server components don’t allow for hooks such as useEffect, see documentation here.

You have two main options:

  1. New way of fetching data
    Server components allow for a new way of fetching data in a component, described here.
    This approach would look something this:

    async function getData() {
      const res = await fetch('https://api.example.com/...');
      // The return value is *not* serialized
      // You can return Date, Map, Set, etc.
    
      // Recommendation: handle errors
      if (!res.ok) {
        // This will activate the closest `error.js` Error Boundary
        throw new Error('Failed to fetch data');
      }
    
      return res.json();
    }
    
    export default async function Page() {
     const data = await getData();
    
     return <main></main>;
    }
    
  2. Revert to client components
    Your other option is to use the use client directive at the top of your file and leaving Newsletter as a client component. Of course, this way, you wouldn’t get the benefits of server components, but this would prevent you from having to change your code substantially. Also, keep in mind that server components are still in beta.

Leave a Reply