Next.js Discord

Discord Forum

pass props from serverside to client side

Answered
Collared Plover posted this in #help-forum
Open in Discord
Collared PloverOP
Hey everyone,

I got a file which gets the users currency using timezones:
"use client"

import { useEffect, useState } from 'react';

export default function CalcPrices({ price }) {
    const [valuta, setValuta] = useState('');

    useEffect(() => {
      const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone
      let detectedCurrency = null;
  
      if (timezone.startsWith('Europe')) {
        detectedCurrency = timezone === 'Europe/London' ? 'gbp' : 'eur';
      } else if (timezone === 'America/Toronto' || timezone === 'America/Vancouver' || timezone === 'America/Edmonton' || timezone === 'America/St_Johns' || timezone === 'America/Winnipeg' || timezone === 'America/Halifax') {
        detectedCurrency = 'cad';
      } else if (timezone.startsWith('Australia')) {
        detectedCurrency = 'aud';
      } else {
        detectedCurrency = 'usd';
      }

      setValuta(detectedCurrency)
    }, []);

    return(
        <p className='text-xl font-medium text-secondary-50'>
            {valuta == "eur" ? `\u20AC${(price * 0.897).toFixed(2)}` :
                <>
                {valuta == "gbp" ? `£${(price * 0.772).toFixed(2)}` :
                    <>
                    {valuta == "aud" ? `AU$${(price * 1.472).toFixed(2)}` :
                        <>
                        {valuta == "cad" ? `CA$${(price * 1.318).toFixed(2)}` :
                            <>
                            {valuta ? <> ${(price * 1).toFixed(2)} </> :
                              <span className='animate-pulse text-lg padding-2 text-secondary-100 bg-secondary-100 rounded'>$2.00</span>
                            }
                            </>
                        }
                        </>
                    }
                    </>
                }
                </>
            }
        </p>
    )
}


The only issue is, the prices are static, I found an API which I can use to get the latest exchange rate. Here is my API script:
export default async function getCurrency(){
    const rep = await fetch('https://api.exchangerate.host/latest?base=usd', { next: { revalidate: 3600 } })
    
    if(!rep.ok) {
        throw new Error('failed to fetch exchange rate');
    }

    return await rep.json()
}


The only issue is, I'm not sure how to pass the props. I tried calling the user currency like this:
{calcPrices} but this doesn't work. I have to use <CalcPrices />, is there a way to expert the currency as a prop instead of component?
Answered by Collared Plover
@riský working 😄
View full answer

86 Replies

as in your importing client component from server component and you want to pass data
you can just use props like normal
@riský you can just use props like normal
Collared PloverOP
No someone I cannot call a client component into a server component. It's maybe due that I use async
But is it possible to export a component as an prop?
@Collared Plover No someone I cannot call a client component into a server component. It's maybe due that I use async
yes you can.. you can import client components into a server component...
ie in this [metadata example](https://nextjs-discord-common-questions.joulev.dev/how-to-set-metadata-to-page-tsx-rendered-as-client-components), it imports it...
// page.client.tsx
"use client";
export default function PageClient() {
  useSomeHook();
  return <Something />;
}
 
// page.tsx
import PageClient from "./page.client";
export default function Page() {
  return <PageClient />;
}
export const metadata = { title: "My Page" };
or have i misunderstood you?
@riský or have i misunderstood you?
Collared PloverOP
So I'm no expert. But I got this script which must run as a client side component. It gets the users currency, and I can make it respond for example: eur

Then I found an API which I use to get the exchange rate, for example USD to EUR response: 0.98
But this must be on server side.

The thing is, I need the value from the client, before I can request the right currency rate.
btw i think this code is the same as yours and looks web simpler
<p className='text-xl font-medium text-secondary-50'>
  {
    valuta === "eur" && <> \u20AC${(price * 0.897).toFixed(2)}</>
    || valuta === "gbp" && <> £${(price * 0.772).toFixed(2)}</>
    || valuta === "aud" && <> AU$${(price * 1.472).toFixed(2)}</>
    || valuta === "cad" && <> CA$${(price * 1.318).toFixed(2)}</>
    || valuta && <> ${(price * 1).toFixed(2)}</>
    || <span className='animate-pulse text-lg padding-2 text-secondary-100 bg-secondary-100 rounded'>$2.00</span>
  }
</p>
Collared PloverOP
Wait I can put an async function into a client component?
no, but you can pass the server action function through props
actually, i think you can directly import the server action into client component
but it must be an async function...
it has a "use server" async function that is imported into the client component and then run
but to simplify things, are you using CalcPrices inside a server component, as you could just pass through the dictionary of prices
But I'm trying something else now
did you get a json error?
Collared PloverOP
no
what error do you get then?
Collared PloverOP
"use client"

import { useEffect, useState } from 'react';
import getCurrency from '../libs/getCurrency';

export default function CalcPrices({ price }) {
    const [valuta, setValuta] = useState('');

    async function onCreate() {
      const res = await getCurrency;
    }

    useEffect(() => {
      const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone
      let detectedCurrency = null;
  
      if (timezone.startsWith('Europe')) {
        detectedCurrency = timezone === 'Europe/London' ? 'gbp' : 'eur';
      } else if (timezone === 'America/Toronto' || timezone === 'America/Vancouver' || timezone === 'America/Edmonton' || timezone === 'America/St_Johns' || timezone === 'America/Winnipeg' || timezone === 'America/Halifax') {
        detectedCurrency = 'cad';
      } else if (timezone.startsWith('Australia')) {
        detectedCurrency = 'aud';
      } else {
        detectedCurrency = 'usd';
      }

      setValuta(detectedCurrency)
    }, []);

    return(
        <p className='text-xl font-medium text-secondary-50'>
            {valuta == "eur" ? `\u20AC${(price * 0.897).toFixed(2)}` :
                <>
                {valuta == "gbp" ? `£${(price * 0.772).toFixed(2)}` :
                    <>
                    {valuta == "aud" ? `AU$${(price * 1.472).toFixed(2)}` :
                        <>
                        {valuta == "cad" ? `CA$${(price * 1.318).toFixed(2)}` :
                            <>
                            {valuta ? <> ${(price * 1).toFixed(2)} </> :
                              <span className='animate-pulse text-lg padding-2 text-secondary-100 bg-secondary-100 rounded'>$2.00</span>
                            }
                            </>
                        }
                        </>
                    }
                    </>
                }
                </>
            }
        </p>
    )
} 
because clearly price is working
Collared PloverOP
wait I maybe got an idea
"use client"

import { useEffect, useState } from 'react';
import ExchangePrice from './ExchangePrice';

export default function CalcPrices({ price }) {
    const [valuta, setValuta] = useState('');

    useEffect(() => {
      const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone
      let detectedCurrency = null;
  
      if (timezone.startsWith('Europe')) {
        detectedCurrency = timezone === 'Europe/London' ? 'gbp' : 'eur';
      } else if (timezone === 'America/Toronto' || timezone === 'America/Vancouver' || timezone === 'America/Edmonton' || timezone === 'America/St_Johns' || timezone === 'America/Winnipeg' || timezone === 'America/Halifax') {
        detectedCurrency = 'cad';
      } else if (timezone.startsWith('Australia')) {
        detectedCurrency = 'aud';
      } else {
        detectedCurrency = 'usd';
      }

      setValuta(detectedCurrency)
    }, []);

    return(
        <ExchangePrice price={price} valuta={valuta}/>
    )
}


import getCurrency from '../libs/getCurrency';

export default async function ExchangePrice({ valuta, price }) {
    const res = await getCurrency()
    
    return(
        <p>
            hey
        </p>
    )
} 
@riský this gives the following error;
you didn't make it server action
iirc you can just put the string at the top like client components to make it server action
"use server"
import getCurrency from '../libs/getCurrency';

export default async function ExchangePrice({ valuta, price }) {

    const res = await getCurrency()
    
    return(
        <p>
            hey
        </p>
    )
}
Collared PloverOP
To use Server Actions, please enable the feature flag in your Next.js config. Read more: https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions#convention
and enable the server action option in config like message says...
@riský and enable the server action option in config like message says...
Collared PloverOP
Yeah I did so
let me check if it works
- error Error: Server Functions cannot be called during initial render. This would create a fetch waterfall. Try to use a Server Component to pass data to Client Components instead.
🤔
can you show where you are calling the client component from...
ahh yeah, it is for action not initial data...
if it is a server component, then you can just do the fetching and pass that to the client?
and if you get an error with that, i have heard you can use JSON.stringify({foo:123}) and pass it as a string and collect with JSON.parse(str)
Collared PloverOP
Uhm, :shy: idk how to pass it to the client component
I tried it too
same way you do price...
Collared PloverOP
as a component?
like where are you using CalcPrices, and how are you setting price?
Collared PloverOP
I'm sorry if I'm saying/doing dumb stuff I'm no expert lol
where is something like this code: <CalcPrices price={} />
@riský where is something like this code: `<CalcPrices price={} />`
Collared PloverOP
That's in the pricecard file
and is that a server component file (ie no "use client")
Collared PloverOP
That was another idea, call both files into the pricecard file and combine it together. But how can I expert the data as props and not asa component?
@riský and is that a server component file (ie no "use client")
Collared PloverOP
it is a client file
But I can easily transform it into a server file
with app dir, you should do as much as possible in the server
and if required, you can just pass the value down many layers (won't look very nice tho)
@riský with app dir, you should do as much as possible in the server
Collared PloverOP
Yeah but the pricecards use a dropdown
whever you closest server component is, i would add the prop of conversions... and pass the props down to every component necessary to get there
Collared PloverOP
But the issue is, I can't export the values as a value, I can only pass them as a component.
So I can't use it for the calculations
im very confused... you can pass the values to each component via props...
but i don't have any other way to explain this, sorry 😭
Collared PloverOP
Uhm, should I add you to my github for a sec?
If you're cool with that off course
I will then transfer my pricecard into a server component
@Collared Plover If you're cool with that off course
... not really... i can help here, but not really with large things... i prefer to not have these things in my github... (sorry)
@Collared Plover I will then transfer my pricecard into a server component
but you can tell me about this on discord 🙂
Collared PloverOP
Alright no problem, let me transfer the pricecard into a server component
Mind moving to DM's? So I don't have to post all my source code public
you can delete it after + don't need to give it all (just the bits in the file that are necessary)
Alrighty so my pricecard is a server component
yay! and it works (at least that part)?
Collared PloverOP
Yeah
And I can request the it with: <CalcPrices price={price}/>
But now I have to get ExchangeRatio and match it with calcprices
yeah, now you can add another prop
Collared PloverOP
CalcPrices is named wrong, it should be UserValuta
@riský yeah, now you can add another prop
Collared PloverOP
to the pricecard?
to CalcPrices (or where you doing calculation)
and in pricecard you do the server request to the api
@riský to CalcPrices (or where you doing calculation)
Collared PloverOP
mhm, but the file which provides the api has multiple responses...
usd -> eur
usd -> gbp
usd -> cad
and like price prop, you put the disctionary there
Collared PloverOP
mhm alright then just use multiple props xd
you can also do that 🙂
Collared PloverOP
@riský working 😄
Answer