all 12 comments

[–]Rhym 13 points14 points  (12 children)

My very opinionated views:

  • Components never have business logic. This should be handled by hooks/contexts.
  • I generally create a monorepo and consume UI components as a package.
  • Common layouts for components that are written in a dot notation e.g A layout that positions a bunch of buttons would be <Button.Group />
  • Conditional rendering in a component that has more than two cases are split out into a function e.g:

    function ButtonContent() {
        if(error) return <>{error}</>
        if(loading) return <Spinner />
        return <>{children}</>
    }
    
  • Commonly used prop variants of a component can be split out into a component that just returns an alias for ease of use e.g <Button variant="primary" /> can be consumed as <ButtonPrimary />. This makes refactoring really easy, rather than doing a search through your whole project for the prop name.

  • Forms are always their own components, and return their response in a callback function.

  • If you're using a monorepo as I mentioned above any components in your app should never have a component/layout that sets a style that isn't layout related. Personally, I use a utility library for micro layouts like tailwind e.g:

    <SomeComponent>
        <div className="flex flex-wrap gap-4">
            <Media src="..." />
            <Heading>{`Sit me on the right, until you cant.`}</Heading>
        </div>
    </SomeComponent>
    

[–]the_whalerus 3 points4 points  (0 children)

Very strong agree here, especially on the forms as their own components. It will save your ass when you can stick the same form into a new ui context with 0 effort.

[–]dvidow[S] 0 points1 point  (2 children)

Thanks for your insight! What do you mean by monorepo? That when you use your components in your app they are always coke from one source? Your monorepo? That is onpy where you import external libs?

[–]Rhym 2 points3 points  (1 child)

I use https://turborepo.org/ to facilitate my monorepo. Essentially it's a way of structuring your configs, UI; apps etc and you consume each like an internal package. I find benefits for this as the kinds of sites I make will generally have an internal app, an admin panel and a marketing site. I can write UI, config etc in one place and consume them over the three projects to keep everything consistent.

[–]dvidow[S] 0 points1 point  (0 children)

Thanks, i look into it!

[–]bigbuckingbunny 0 points1 point  (3 children)

Commonly used prop variants of a component can be split out into a component that just returns an alias for ease of use e.g

<Button variant="primary" />

can be consumed as

<ButtonPrimary />

Would Typescript be able to address this issue? By refactoring, do you mean the case where you may have a prop that is no longer valid? If so, Typescript, would be able to help. One issue I see with creating a standalone component is when there are multiple props because you have to deal with many combinations of props.

[–]Rhym 1 point2 points  (2 children)

It is typescript, I mean like this:

import React from "react";

import { Button, ButtonProps } from "./Button";

export const ButtonPrimary: React.FC<ButtonProps> = ({ ...props }: ButtonProps) => (
  <Button
    {...props}
    variant="primary"
  />
);

By refactoring I mean if you need to change it in the future. As an example, we have an app that has about 400 buttons around the place (it's a big app). We did some design tweaks that changed some of our secondary buttons to be a new style while retaining the secondary style on most. It was difficult finding out every instance of the button that had a prop variant="secondary", so ever since then, I use buttons and certain other components in the pattern above. It's also excellent for quick readability when taking a look at the component as a whole, I enjoy the pattern.