skip to Main Content

I have a component at apppage.tsx in Next.js v13.4.12, containing a button. When I click on it, I want it to call the handleClick func.

But the function getInitialProps is not called and doesn’t send props to the Page component, what should I do?

In fact, I want when the page render for the first time, even if we are not clicking on the button, data render on the page.

'use client'
import { useState } from 'React';

export default function Page({ initialData }) {
    const [data, setData] = useState(initialData);

    const fetchData = async () => {
        const req = await fetch('https://randomuser.me/api/?gender=male&results=100');
        const newData = await req.json();

        return setData(newData.results);
    };

    const handleClick = (event) => {
        event.preventDefault();
        fetchData();
    };

    return (
        <Layout>
            <button onClick={handleClick}>FETCH DATA</button>
            {data.map((user) => {
                return (
                    <div>
                        {user.email}
                        <img src={user.picture.medium} alt="" />
                    </div>
                );
            })}
        </Layout>
    );
}

Page.getInitialProps = async () => {
    const req = await fetch('https://randomuser.me/api/?gender=female&results=10');
    const data = await req.json();
    return { initialData: data.results };
};

2

Answers


  1. Methods like getServerSideProps and getStaticProps are for fetching data on the server but they only work for page components inside the pages folder (the initial way of setting up routes in Next.js).

    Since Next.js 13, in the app directory, we have Server Components, where you can fetch data directly in the component body, where what you want to achieve would be done as below (notice the additional file created):

    // app/page.js 👈🏽
    
    import Users from "./users";
    
    export default async function Page() {
      const req = await fetch("https://randomuser.me/api/?gender=female&results=10");
      const data = await req.json();
    
      return <Users initialUsers={data.results} />;
    }
    

    You need the below additional component because you need client interactivities (an onClick handler here), which you cannot have in the server Page component above.

    // app/users.js 👈🏽
    
    "use client";
    
    import { useEffect, useState } from "react";
    
    export default function Users({ initialUsers }) {
      const [data, setData] = useState(initialUsers);
    
      const handleClick = async (event) => {
        event.preventDefault();
        const req = await fetch("https://randomuser.me/api/?gender=male&results=100");
        const newData = await req.json();
        setData(newData.results);
      };
    
      return (
        <div>
          <button onClick={handleClick}>FETCH DATA</button>
          {data.map((user, index) => {
            return (
              <div key={index}>
                {user.email}
                <img src={user.picture.medium} alt="" />
              </div>
            );
          })}
        </div>
      );
    }
    

    Otherwise, because your page is already a client component with "use client" at the top, you could simply use an useEffect to load the initial data, like so:

    // app/page.js 👈🏽
    
    "use client";
    
    import { useEffect, useState } from "react";
    
    export default function Page() {
      const [data, setData] = useState([]);
    
      const handleClick = async (event) => {
        event.preventDefault();
        const req = await fetch("https://randomuser.me/api/?gender=male&results=100");
        const newData = await req.json();
        setData(newData.results);
      };
    
      useEffect(() => {
        fetch("https://randomuser.me/api/?gender=female&results=10")
          .then((res) => res.json())
          .then((data) => {
            setData(data.results);
          });
      }, []);
    
      return (
        <div>
          <button onClick={handleClick}>FETCH DATA</button>
          {data.map((user, index) => {
            return (
              <div key={index}>
                {user.email}
                <img src={user.picture.medium} alt="" />
              </div>
            );
          })}
        </div>
      );
    }
    
    Login or Signup to reply.
  2. getInitialProps is now a legacy API and the documentation recommends using getStaticProps and getServerSideProps. But since both are not supported in app router, try this instead:

    Create a server component as a parent where you fetch the initial data and then pass it to the client component where all the client-side operations can be handled.

    Server Component

    export async function ServerComponent() {
        const req = await fetch('https://randomuser.me/api/?gender=female&results=10');
        const data = await req.json();
    
        return (
            <ClientComponent initialData={data.results} />
        )
    
    }
    

    Client Component

    "use client";
    
    export function ClientComponent({ initialData }) {
    const [data, setData] = useState(initialData);
    
      const fetchData = async () => {
        const req = await fetch(
          "https://randomuser.me/api/?gender=male&results=100"
        );
        const newData = await req.json();
    
        return setData(newData.results);
      };
    
      const handleClick = (event) => {
        event.preventDefault();
        fetchData();
      };
    
      return (
        <div>
          <button onClick={handleClick}>FETCH DATA</button>
          {data.map((user) => {
            return (
              <div>
                {user.email}
                <img src={user.picture.medium} alt="" />
              </div>
            );
          })}
        </div>
      );
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search