Search code examples
next.jsonclickprismareact-server-components

How to allow user to click an item from a server-rendered list in Next.js/React?


pretty new to react/next.js and am having trouble with something I assume is pretty basic. However, I can't seem to find any answers that apply to my specific situation.

Basically, on page load I have a component that returns a list of songs with artist names via a simple prisma query. I would like the user to be able to click on a song, and for the sake of simplicity, display the song name and artist name in the console. What do I do? Here's the code for the component "StemList" that returns the list of songs:

import prisma from "@/components/stemdatabase"
export async function getStems(stemType) {
    return prisma.stems.findMany({
        where: {
            stem_type: stemType
        }
    })
}

export default async function StemList({ stemType }) {
    const stems = await getStems(stemType)

    return (
        <>
            {stems.map((stem) => (
                <ul className='song-title' key={stem.id} stemType={stemType}>
                    {stem.song_name} - {stem.artist_name}
                </ul>
            ))}
        </>
    )
}

I tried including an onClick property, but I quickly found out that this cannot be used on a server side component. I also can't convert this to a client component because I'm querying my db file. I can't seem to find a suitable/easy alternative to onClick, even though I feel like this should be a pretty basic bit of functionality.


Solution

  • You can wrap a client component inside a server component and then pass your list as a prop through to the client.

    Your server component loads the list:

    import prisma from "@/components/stemdatabase"
    
    export async function getStems(stemType) {
        return prisma.stems.findMany({
            where: {
                stem_type: stemType
            }
        })
    }
    
    export default async function StemList({ stemType }) {
        const stems = await getStems(stemType)
        return <InteractiveStemList stems={stems} stemType={stemType} />
    }
    

    And your client component makes it interactive:

    "use client";
    
    export default function InteractiveStemList({ stems, stemType }) {
        return (
            <ul>
                {stems.map((stem) => (
                    <li className='song-title' key={stem.id} stemType={stemType}>
                        <a onClick={/* callback goes here */}>{stem.song_name} - {stem.artist_name}</a>
                    </li>
                ))}
            </ul>
        )
    }
    

    You can also use server actions to make your click trigger something on the server side.