Using user component in server component React

Using user component in server component React
reactjs
Ethan Jackson

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.

Related Articles