Using user component in server component React

Problem
I want to add events to a client component that has a server component as a parent component, but I get an error.
Message Error:
Error: Event handlers cannot be passed to Client Component props. <... className=... onChange={function}> ^^^^^^^^^^ If you need interactivity, consider converting part of this to a Client Component.
Things I've tried
- I created an "intermediary" file, we could call it, but as I imagined, the same thing happened.
- I tried to make the parent component the client component, but it asks me that it must be a server component.
- I tried to make the "Input" component a server component, but the problem is in the tag that comes by default from HTML, which is a client component.
Explication
I have a parent component that is a server component since it will make connections to the database, which is the following:
"use server"
import "./Filtro.css"
import { EntityMetadata, EntityTarget, ObjectLiteral } from "typeorm"
import { GetColumns } from "@/SQL/SQLManager"
import { Calendar } from "../Calendar/Calendar"
import { Circle } from "../Polygons/Circle/Circle"
import Image from "next/image"
import { ColumnSearch } from "./_components/ColumnSearch/ColumnSearch"
type FilterProps<T> = {
entity: EntityTarget<T>,
except?: string[]
}
export async function Filter<T extends ObjectLiteral>({ entity, except } : FilterProps<T>) {
const columns = (await GetColumns(entity))
.filter((column) =>
except != null ? except.indexOf(column.propertyName) : true
);
const changeEvent = (value: string) => {
console.log(value);
}
return (
<div className="filter-container">
<div className="flex items-center gap-3.5 mb-3.5">
{/* <div className="filter-circle"></div> */}
<Circle width={40} height={40} className="bg-primary"/>
<h2 className="text-2xl font-bold">Filtros</h2>
</div>
<div className="bg-section rounded-xl px-4 py-5">
{
columns.map((column) => {
return <ColumnSearch
entity={entity}
column={column}
className="bg-white text-black p-1.5 rounded-xl"
onInputChange={changeEvent}
/>
})
}
<div className="relative mt-3.5">
<input type="text" className="filter-input p-2.5 rounded-3xl" placeholder="Buscar"/>
<Image className="filter-magnifier" src="/white/svg/Magnifier.svg" width="24" height="24" alt="Magnifier"/>
</div>
</div>
</div>
)
}
But the object it calls (ColumnSearch) is also a server object, which can be either an Input or a Calendar, here is the code:
import { Calendar } from "@/components/Calendar/Calendar"
import { EntityTarget, ObjectLiteral } from "typeorm"
import { ColumnMetadata } from "typeorm/metadata/ColumnMetadata.js"
import './ColumnSearch.css'
import { Input } from "@/components/Input/Input"
type ColumnSearchProps<T> = {
entity: EntityTarget<T>,
column: ColumnMetadata,
className?: string,
onInputChange?: (value: string) => void
}
export async function ColumnSearch<T extends ObjectLiteral>({ entity, column, className, onInputChange } : ColumnSearchProps<T>) {
console.log(column.type)
return <div className='filter-option relative flex justify-between items-center cursor-pointer text-lg py-3.5'>
{column.propertyName.replace("_", " ")}
{
column.type != Date ?
<Input className={className}/> : //onChange={onInputChange ? (e) => onInputChange(e.target.value) : undefined}
<Calendar className={className}/>
}
</div>
}
But the component that calls ColumnSearch (Input) is actually an HTML input and this is a client component, the problem is that I want to add events to it but it won't let me because the parent component is a server component, here is the code:
"use client"
import { ChangeEventHandler, RefObject, useRef } from "react"
type InputProps = {
className?: string,
onChange?: ChangeEventHandler<HTMLInputElement>,
ref?: RefObject<HTMLInputElement>
}
export function Input({ className, onChange, ref } : InputProps) {
return <input className={className} onChange={onChange} ref={ref}/>
}
Answer
You can not.
Event handlers cannot be passed to Client Component, if you need interactivity, consider converting part of this to a Client Component.
In Nextjs, a server component can not pass a function to a client component.
Why not converting ColumnSearch to a client component? You can pass the data to your client component, and let it handle DOM logic.
If you want to keep Filter component as a server component responsible of fetching your data, it should not handle UI events..etc Let client components handle the UI.
Enjoyed this article?
Check out more content on our blog or follow us on social media.
Browse more articles