Next.js Discord

Discord Forum

Functions cannot be passed directly to Client Components

Unanswered
Da_v_id posted this in #help-forum
Open in Discord
export default async function RootLayout({
  children,
  params: { locale },
}: Readonly<{
  children: React.ReactNode;
  params: {
    locale: Locale;
  };
}>) {
  const translatedData = await getTranslatedData(locale);
  return (
    <html lang={locale} suppressHydrationWarning>
      <body
        className={cn(
          "min-h-screen bg-background font-sans antialiased max-w-2xl mx-auto py-12 sm:py-24 px-6",
          fontSans.variable
        )}
      >
        <TranslatedDataProvider translatedData={translatedData}>
          <ThemeProvider attribute="class" defaultTheme="light">
            <TooltipProvider delayDuration={0}>
              {children}
              <Navbar />
            </TooltipProvider>
          </ThemeProvider>
        </TranslatedDataProvider>
      </body>
    </html>
  );
}


how come as soon as I add await to getTranslatedData which is flagged with "use server" I immediately get this error:
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.
  {$$typeof: ..., render: function Home}


if I remove it, it works but what is the point of having a promise in the context provider?

74 Replies

@Da_v_id you can't pass function directly to the client component. what you can pass to the client component server actions
the correct way to do this is to make a client component with all of your providers
I understand but where in this code I am passing a function to a client component? If I wait for the promise i should just pass the resulting string, right?
the problem arise when i put the 'await' in front of my promise
can you show me the TranslatedDataProvider component?
here:

"use client"

import { getTranslatedData } from "@/data/resume"
import React from "react"

type TranslatedData = ReturnType<typeof getTranslatedData>

const TranslatedDataContext = React.createContext<TranslatedData | null>(null)

export default function TranslatedDataProvider({
  translatedData,
  children,
}: {
  translatedData: TranslatedData
  children: React.ReactNode
}) {
  return (
    <TranslatedDataContext.Provider value={translatedData}>
      {children}
    </TranslatedDataContext.Provider>
  )
}

export function useTranslatedData() {
  const translatedData = React.useContext(TranslatedDataContext)
  if (translatedData === null) {
    throw new Error('useTranslatedData hook must be used within TranslatedDataProvider')
  }

  return translatedData
}
I also tried to play around with TranslatedData type and put Awaited<ReturnType<typeof getTranslatedData> when I wait for the data in the layout
import { getTranslatedData } from "@/data/resume"
what's this line for?
oh it's just used for the type
wait @Da_v_id do you have "use server" in getTranslateData function?
show me that function
import { getTranslatedData } from "@/data/resume"
show me this file
i do have and it looks like this:
"use server";
import { getDictionary } from '@/lib/getDictionaries';
export const getTranslatedData = async (locale: Locale) => {
  const intl = await getDictionary(locale);

  const getDescription = (descriptions: MultiLanguage) => {
    return descriptions[locale] || descriptions['en'];
  };
  return ({...})


and getDictionary:
import 'server-only'
import { i18n, Locale } from '@/lib/i18-config'

const dictionaries = {
  it: () => import('@/dictionaries/it.json').then((module) => module.default),
  en: () => import('@/dictionaries/en.json').then((module) => module.default),
}

export const getDictionary = async (locale: Locale) => dictionaries[i18n.locales.includes(locale) ? locale : i18n.defaultLocale]()
okay so @Da_v_id "use server" is used wrongly
"use server" is like a door to the server from the client side
it should be used for server actions
right, I have actually played around with that too, and if i remove it the result will be the same
okay anyway, we should remove "use server"
and you still get the same error?
done, thank you!
can you create a separate typescript file for the interfacecs and types for the function and import types from there?
@Da_v_id
try it then, remove the import line
like this:
"use client"

import type { getTranslatedData } from "@/data/resume"
import React from "react"

type TranslatedData = ReturnType<typeof getTranslatedData>

const TranslatedDataContext = React.createContext<TranslatedData | null>(null)

export default function TranslatedDataProvider({
  translatedData,
  children,
}: {
  translatedData: TranslatedData
  children: React.ReactNode
}) {
  return (
    <TranslatedDataContext.Provider value={translatedData}>
      {children}
    </TranslatedDataContext.Provider>
  )
}

export function useTranslatedData() {
  const translatedData = React.useContext(TranslatedDataContext)
  if (translatedData === null) {
    throw new Error('useTranslatedData hook must be used within TranslatedDataProvider')
  }

  return translatedData
}

I get the same error :/
nope,
import type { getTranslatedData } from "@/data/resume"
pardon
remove this line, don't try to import functions into client component
'use client'

import React from "react"

type TranslatedData = Awaited<ReturnType< any>>

const TranslatedDataContext = React.createContext<TranslatedData | null>(null)

export default function TranslatedDataProvider({
  translatedData,
  children,
}: {
  translatedData: TranslatedData
  children: React.ReactNode
}) {
  return (
    <TranslatedDataContext.Provider value={translatedData}>
      {children}
    </TranslatedDataContext.Provider>
  )
}

export function useTranslatedData() {
  const translatedData = React.useContext(TranslatedDataContext)
  if (translatedData === null) {
    throw new Error('useTranslatedData hook must be used within TranslatedDataProvider')
  }

  return translatedData
}
"use client"


import React from "react"

const TranslatedDataContext = React.createContext<any | null>(null)

export default function TranslatedDataProvider({
  translatedData,
  children,
}: {
  translatedData: any
  children: React.ReactNode
}) {
  return (
    <TranslatedDataContext.Provider value={translatedData}>
      {children}
    </TranslatedDataContext.Provider>
  )
}

export function useTranslatedData() {
  const translatedData = React.useContext(TranslatedDataContext)
  if (translatedData === null) {
    throw new Error('useTranslatedData hook must be used within TranslatedDataProvider')
  }

  return translatedData
}
should be Awaited?
nope, it's a client component, sync function
I used your snippet but still this error
it's so weird
show me the file as a screenshot?
export async function generateStaticParams() {
  return [{ lang: 'en-US' }, { lang: 'it' }]
}

export default async function RootLayout({
  children,
  params: { locale },
}: Readonly<{
  children: React.ReactNode;
  params: {
    locale: Locale;
  };
}>) {
  const translatedData = await getTranslatedData(locale);
  return (
    <html lang={locale} suppressHydrationWarning>
      <body
        className={cn(
          "min-h-screen bg-background font-sans antialiased max-w-2xl mx-auto py-12 sm:py-24 px-6",
          fontSans.variable
        )}
      >
        <TranslatedDataProvider translatedData={translatedData}>
          <ThemeProvider attribute="class" defaultTheme="light">
            <TooltipProvider delayDuration={0}>
              {children}
              <Navbar />
            </TooltipProvider>
          </ThemeProvider>
        </TranslatedDataProvider>
      </body>
    </html>
  );
}
which file?
TranslatedDataProvider.tsx
do we get the same error if we comment out <TranslatedDataProvider> layer in the layout.tsx?
export async function generateStaticParams() {
  return [{ lang: 'en-US' }, { lang: 'it' }]
}

export default async function RootLayout({
  children,
  params: { locale },
}: Readonly<{
  children: React.ReactNode;
  params: {
    locale: Locale;
  };
}>) {
  //const translatedData = await getTranslatedData(locale);
  return (
    <html lang={locale} suppressHydrationWarning>
      <body
        className={cn(
          "min-h-screen bg-background font-sans antialiased max-w-2xl mx-auto py-12 sm:py-24 px-6",
          fontSans.variable
        )}
      >
        <ThemeProvider attribute="class" defaultTheme="light">
          <TooltipProvider delayDuration={0}>
            {children}
            <Navbar />
          </TooltipProvider>
        </ThemeProvider>
      </body>
    </html>
  );
}
no it works!
but i can't access the data in client components from the context :/
yeah, ofc just wanted to check if it's really due to that provider
oh then I guess it is
can we have the provider component and hook in different files? not sure if it's the reason but looks off
but also as said if i keep the provider and remove "Await" it works
remove await? but it's async function I remember from your code
then it means it's not async function indeed
I splitted the hook and provider:
oh, you have json, not loading from the file
then it should be sync
why is it async?
@Da_v_id I splitted the hook and provider:
Okay I believe that's a good practice
you mean i should remove async?
yeah, try that
still same issue:
Done, I am so dumb, I had to stringify the data before passing them to the provider...
I am so sorry for wasting your time :/
no worries, just mark your solution
so that others can easily know what's that