#pass props from serverside to client side

88 messages · Page 1 of 1 (latest)

strong stream
#

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:
```js
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?
sour raptorBOT
#

🔎 This post has been indexed in our web forum and will be seen by search engines so other users can find it outside Discord

🕵️ Your user profile is private by default and won't be visible to users outside Discord, if you want to be visible in the web forum you can add the "Public Profile" role in id:customize

✅ You can mark a message as the answer for your post with Right click -> Apps -> Mark Solution
(if you don't see the option, try refreshing Discord with Ctrl + R)

rotund panther
#

as in your importing client component from server component and you want to pass data

#

you can just use props like normal

strong stream
#

But is it possible to export a component as an prop?

rotund panther
#

ie in this metadata example, 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?

strong stream
# rotund panther or have i misunderstood you?

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.

rotund panther
#

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>
strong stream
rotund panther
strong stream
#

Wait I can put an async function into a client component?

rotund panther
#

no, but you can pass the server action function through props

#

actually, i think you can directly import the server action into client component

strong stream
#

but it must be an async function...

rotund panther
#

it has a "use server" async function that is imported into the client component and then run

rotund panther
#

but to simplify things, are you using CalcPrices inside a server component, as you could just pass through the dictionary of prices

strong stream
#

But I'm trying something else now

rotund panther
#

did you get a json error?

strong stream
#

no

rotund panther
#

what error do you get then?

strong stream
#
"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>
    )
} ```
rotund panther
#

because clearly price is working

strong stream
#

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}/>
    )
}```

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

export default async function ExchangePrice({ valuta, price }) {
    const res = await getCurrency()
    
    return(
        <p>
            hey
        </p>
    )
} ```
#

@rotund panther this gives the following error;

rotund panther
#

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>
    )
}
strong stream
#

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

rotund panther
#

and enable the server action option in config like message says...

strong stream
#

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.

#

🤔

rotund panther
#

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)

strong stream
#

Uhm, shy idk how to pass it to the client component

#

I tried it too

rotund panther
#

same way you do price...

strong stream
#

as a component?

rotund panther
#

like where are you using CalcPrices, and how are you setting price?

strong stream
#

I'm sorry if I'm saying/doing dumb stuff I'm no expert lol

rotund panther
#

where is something like this code: <CalcPrices price={} />

strong stream
rotund panther
#

and is that a server component file (ie no "use client")

strong stream
#

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?

strong stream
#

But I can easily transform it into a server file

rotund panther
#

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)

strong stream
rotund panther
#

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

strong stream
#

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

rotund panther
#

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 😭

strong stream
#

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

rotund panther
rotund panther
strong stream
#

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

rotund panther
#

you can delete it after + don't need to give it all (just the bits in the file that are necessary)

strong stream
#

Alrighty so my pricecard is a server component

rotund panther
#

yay! and it works (at least that part)?

strong stream
#

Yeah

#

And I can request the it with: <CalcPrices price={price}/>

#

But now I have to get ExchangeRatio and match it with calcprices

rotund panther
#

yeah, now you can add another prop

strong stream
#

CalcPrices is named wrong, it should be UserValuta

strong stream
rotund panther
#

to CalcPrices (or where you doing calculation)

#

and in pricecard you do the server request to the api

strong stream
rotund panther
#

and like price prop, you put the disctionary there

strong stream
#

mhm alright then just use multiple props xd

rotund panther
#

you can also do that 🙂

strong stream
#

@rotund panther working 😄