Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Badge' cannot be used as a JSX component #16

Open
Kyle772 opened this issue Mar 9, 2023 · 5 comments
Open

Badge' cannot be used as a JSX component #16

Kyle772 opened this issue Mar 9, 2023 · 5 comments

Comments

@Kyle772
Copy link

Kyle772 commented Mar 9, 2023

I'm getting this error while trying to use this on a typescript project. This error exists in the current project demo in the read me so I think something in the spec changed sometime over the last couple of months.

Badge' cannot be used as a JSX component.
  Its return type 'Promise<Element>' is not a valid JSX element.
    Type 'Promise<Element>' is missing the following properties from type 'ReactElement<any, any>': type, props, keyts(2786)
@NWylynko
Copy link
Owner

NWylynko commented Mar 9, 2023

Hey @Kyle772, thanks for making an issue, this is essentially an issue with the current types in react. This module uses the new React Server Components feature that only some environments like Next.js app dir, maybe remix i'm not sure and some other react servers. You can read about them here https://beta.nextjs.org/docs/rendering/server-and-client-components#why-server-components, https://reactjs.org/blog/2020/12/21/data-fetching-with-react-server-components.html and https://remix.run/blog/react-server-components. Additionally Theo did a video on it a couple months ago https://www.youtube.com/watch?v=h_9Vx6kio2s. If you are using an environment that can run them, this type issue should be just ignored. You can either disable typechecking, but i don't recommend that, or add {/* @ts-expect-error Server Component */} above the component until the react types get updated. If you're not using a ssr environment your free to experiment with using an older version of this module, they should have the majority of the badges you could need.

@Kyle772
Copy link
Author

Kyle772 commented Mar 9, 2023

Thank you for the info!

I am running this in Next 13 and I think my problem is stemming from me wrapping a Badge with additional elements in a more generic component which I am rendering on a page. I think I need to look more deeply into next's implementation of server components.

@NWylynko
Copy link
Owner

NWylynko commented Mar 9, 2023

From what your saying i'm guessing your attempting to use a server component inside a client component, this unfortunately isn't possible, the best you can do is pass server components in as children props to a client component. Essentially you should be using server components as far down the tree as possible and really only have small client components that are literally just a button and its handler or a form and its submit logic. I don't love this nature of react/next but its what we got.

@Kyle772
Copy link
Author

Kyle772 commented Mar 14, 2023

Okay so I've gone ahead and developed my implementation further with success but I'm constantly running into issues stemming from this component now that it's been converted to a server component. For example, if I have a list of technologies on a project and I only want to show 3 until someone clicks on it to show the full list that is no longer possible (as far as I can tell) since the client needs to be able to conditionally render them. It doesn't make sense to me to drill these components all the way down from the server component layout level and that seems to be the only way to get anything beyond basic rendering now.

That said I really feel like this library doesn't NEED to be a server component. It really limits where and how this is implemented. I'm likely going to downgrade in the meantime but I think you should reconsider setting this to server only.

Looking through the React server components docs my interpretation of the reasoning for server components is to save on performance wherever possible. Since these components are served as images your browser can just cache and reuse them. Maybe a second version should be added to the library to allow for client-side usage? Just some food for thought.

I may be wrong here since I'm still figuring out server components but I feel like a developer can just wrap the client only component with a server component in their project to get the same functionality IF they want it. The same can't be said going the other direction.

@NWylynko
Copy link
Owner

NWylynko commented Mar 15, 2023

I'm not trying to defend RSC, they seem to have shortcomings and are still very beta. But the reason I decided to use them is fairly simple, as part of this package I needed to know the primary / accent / branding colour of every icon / brand. This project runs a script to grab it from some other source that has done all the work (I don't claim to have done it at all) and compiles it in to one massive json file.

  • The issue is the file size of that json file, with over 1500 icons its very large, not something I thought we would want to put on to the client. But that was my first implementation which worked ok.
  • So to combat this I built an api, very simply it would hold the json object in memory, and you could request the hex for a brand, very simple. Issue being to display any badge now required two network requests, plus I would potentially have to pay for the hosting but eh.
  • The next option I explored was using scripts to generate a new component for every single badge, taking advantage of tree shaking so people could use just the badges they want. Issue here was generating 1500 component .tsx files and compiling that to javascript files.
  • Lastly I rebuilt it using RSC, nextjs, remix, etc is responsible for the json object in memory and only sends the relevant data for the requested components to the client. So far this solves all the above issues, small client bundles, no double request, easy to build and distribute

On to the issues your facing, I totally see where your coming from, so all I can do is offer some solutions. Firstly with the app dir, you should aim to have pretty much everything server components, except for about 3 things: context, buttons and forms. those buttons and forms should be in seperate files with the "use client" at the top. Pretty much everything else should be server rendered. When it comes to holding state, you should put the state in the url, cookies, or hold them server-side.
I totally see that this isn't optimal for every project, all i'm offering is the knowledge i've gained working with the app dir and how it seems nextjs is pushing.

With client side conditional rendering, I don't love how its supposed to be done now, but its not terrible.

      <SummaryTabs
        paragraph={
          <Suspense fallback={<TextSkeleton title="Summary" />}>
            {/* @ts-expect-error RSC Yay */}
            <Summary topic={params.topic} />
          </Suspense>
        }
        dotPoints={
          <Suspense fallback={<TextSkeleton title="Summary" />}>
            {/* @ts-expect-error RSC Yay */}
            <DotPointSummary topic={params.topic} />
          </Suspense>
        }
      />

Heres an example of what I just implemented in a project. This jsx is inside a server component, but SummaryTabs is a client component, with Summary and DotPointSummary being server components. So with SummaryTabs holding state client side, users can click on the tabs to switch between the two server components. In practice it works pretty well. You could even build this in to something more dynamic, taking an array of objects of tab name and component. But really should store the state of the tabs in the url.
In the case of expanding a view to the user on click, a client component that takes the server component as children or a prop would probably work well.

On to your last point, I definitely see the possibility of two components and helper functions / hooks. A base level client component that requires the hex as a prop, then server component that wraps it to supply it, and other functions or hooks to grab the value from the api or you could load it yourself from the json file if thats the way people want to use it. When i've got some free time I'll look in to it.

Of course your completely free in the meantime to go to an older version of the module, they should still work fine. But if you want any help with specifics I'm more than happy to help out.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants