In Next.js, especially when using the new app directory structure, you might encounter the following error when attempting to pass a function from a Server Component to a Client Component:
Thank me by sharing on Twitter 🙏
Error: Functions cannot be passed directly to Client Components unless you explicitly expose it by marking it with "use server".
Or maybe you meant to call this function rather than return it.
<... customers={[...]} mergeCustomers={function mergeCustomers}>
This error happens because Next.js enforces a strict separation between server-side and client-side code. Server-side functions can’t be passed directly to Client Components, as they belong to different environments. To resolve this, you need to explicitly mark the server-side function with use server
and handle the function passing properly.
Why Does This Error Happen?
In Next.js, functions that involve server-side operations (like fetching data or interacting with databases) should not be passed directly to Client Components. Client Components are rendered in the browser, which doesn’t have access to the server-side logic. The solution is to mark these server-side functions with use server
and ensure they are only called from the server.
Solution: Use use server
and Pass the Function from the Page Component
Let’s walk through how to fix this error by marking the function as a server-side function and passing it down to the Client Component properly, where it will be called upon a button click.
1. Create a Server-Side Function
Start by creating the server-side function in its own file. This function will handle any logic that should only be run on the server (e.g., interacting with a database or fetching external data). Make sure to add use server
at the top of the file to declare that it should run server-side.
4Pack [Apple MFi Certified] Charger Lightning to USB Charging Cable Cord Compatible iPhone 14/13/12/11 Pro/11/XS MAX/XR/8/7/6s Plus,iPad Pro/Air/Mini,iPod Touch
$8.49 (as of January 22, 2025 11:32 GMT +00:00 - More infoProduct prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on [relevant Amazon Site(s), as applicable] at the time of purchase will apply to the purchase of this product.)Brother Genuine Standard Yield Toner Cartridge, TN730, Replacement Black Toner, Page Yield Up To 1,200 Pages, Amazon Dash Replenishment Cartridge,1 Pack
$47.98 (as of January 22, 2025 11:32 GMT +00:00 - More infoProduct prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on [relevant Amazon Site(s), as applicable] at the time of purchase will apply to the purchase of this product.)Co-Intelligence: Living and Working with AI
$17.79 (as of January 22, 2025 11:32 GMT +00:00 - More infoProduct prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on [relevant Amazon Site(s), as applicable] at the time of purchase will apply to the purchase of this product.)Here’s an example:
// src/lib/mergeCustomers.js
"use server";
export async function mergeCustomers(customers) {
// Your server-side logic for merging customers
return customers.map(customer => ({
...customer,
merged: true, // Example modification
}));
}
By marking it with use server
, you’re telling Next.js that this function should only run on the server.
2. Pass the Function to the Page Component
In your page file, you can import this server-side function and pass it down to the Client Component. Instead of executing the function on the server, you’ll pass it to the Client Component where it will be called upon a button click.
// src/app/page.js
import { mergeCustomers } from '../lib/mergeCustomers';
import ClientComponent from './ClientComponent';
export default async function Page() {
const customers = await getCustomers(); // Fetch data or initialize customers array
return (
<ClientComponent customers={customers} mergeCustomers={mergeCustomers} />
);
}
In this example, the mergeCustomers
function is passed down as a prop to the ClientComponent
. The Client Component will handle calling the function.
3. Call the Function from the Client Component on a Button Click
Now, update your ClientComponent
to take the mergeCustomers
function as a prop and call it on a button click. This allows the client to trigger the server-side function when needed.
// src/app/ClientComponent.js
import { useState } from 'react';
export default function ClientComponent({ customers, mergeCustomers }) {
const [mergedCustomers, setMergedCustomers] = useState(customers);
const handleMerge = async () => {
const result = await mergeCustomers(mergedCustomers);
setMergedCustomers(result); // Update the state with the merged customers
};
return (
<div>
<h1>Customer List</h1>
<ul>
{mergedCustomers.map(customer => (
<li key={customer.id}>{customer.name} - {customer.merged ? "Merged" : "Not Merged"}</li>
))}
</ul>
<button onClick={handleMerge}>Merge Customers</button>
</div>
);
}
In this updated version of ClientComponent
, when the “Merge Customers” button is clicked, the mergeCustomers
function is called, and the resulting data is used to update the component’s state and re-render the UI.
Verifying the Fix
To verify that the solution works, run the application. The Client Component should render the customer list as expected. When you click the “Merge Customers” button, the customer list should update to show the merged status, and the error about passing functions directly to Client Components should no longer appear.
Conclusion
By marking the server-side function with use server
and passing it down to the Client Component where it is triggered through user interaction, you can resolve the error. This approach ensures that server-side logic is kept separate from client-side code while still allowing interaction between the two when necessary.
This method is a best practice in Next.js, especially in the app directory, where the separation of client and server code is critical for performance and maintainability.
Tags/Keywords: Next.js, Client Components, Server Components, JavaScript, Error Handling, React.