DEV Community

Joshua Okechukwu
Joshua Okechukwu

Posted on

Component design and structure with React Typescript. — Thinking about components from an architectural point of view — part 1

A while back I was onboarded to a small team working on a large project, building a software solution in the health and fitness category. I was brought on as a replacement for a former developer. As I begun working on the project and trying to beat already late deadlines, I noticed the absence of structure and co-ordination in the codebase. There was no clear pattern, components were duplicated and everything was cluttered. This made working on the project quite frustrating for the first month and made it a painful experience all-together.

However, after a month of trying what I could to beat the deadlines and meet up with current requirements, I finally had time to redesign and refactor the code base.

This is the first part of my process. I’ll break it down into a 3 part series

  1. Treat components as atoms first
  2. Typescript polymorphism
  3. Proper style handling
  4. Data handling higher order components (HOCs)

atoms, molecules, organisms template and pages

— Treat components as atoms first

There’s a common line of thought, that one of the skills that gets fine tuned as you gain experience as a developer is deciding what should be a component or not. Even though I agree, I still think there are simple pointers that could guide anyone regardless of experience level.

When you look at a design for a project in Figma for instance, you can make your life easier before you start writing code by studying the design. Take the time to go through the UI design, this could be done together as a team or alone on a solo project.

Youtube home-screen screenshot showing components
Youtube home-screen screenshot showing components

From the image above you can see that the page is actually made up of different bits and pieces, this is general knowledge in react or any other javascript framework. Now with this idea in mind, let’s take a look at another screen and see how components can be atoms.

Credit — https://dribbble.com/ahmdyassr
Credit — https://dribbble.com/ahmdyassr

From the above screen we can see obvious reuse of components and sections (layout). For a single page like this, one could argue that you don’t need to break things into atomic components. But what happens when we’re faced with a large application that has several forms like this in different areas of the application being worked on by different teams?. The need for structure and consistency is suddenly necessary if we intend to keep our application manageable and scalable.

An example of a simple text input in our application can look like this —

interface ITextInput {
  icon?: React.ReactNode;
  placeholder: string;
  value: string;
  onchange: Dispatch<string>;
  type?: string;
  name: string;
}

const TextInput = ({
  icon,
  placeholder,
  value,
  onchange,
  type,
  name,
}: ITextInput) => {
  return (
    <div>
      {icon}
      <input
        placeholder={placeholder}
        type={type || 'text'}
        value={value}
        onChange={({ target }) => onchange(target.value)}
      />
    </div>
  );
};
export default TextInput;
Enter fullscreen mode Exit fullscreen mode

The size and simplicity of this components is what makes this component truly reusable. Styling could be done easily with CSS, any UI library. This way, we just have this small piece of code in our project that is solely responsible for allowing users enter texts. We could do this with buttons, section headers, links and any thing we see used repeatedly across an application. This way, we could have a team solely responsible for building general components(atoms) like this based on our design system.

Atoms lead to molecules

Molecules are still small components but with more parts than an atom and would probably contain two or more atoms. Consider things like cards, modals, toasts, banners. Now your application is coming together. You now have a component “Modal” that you can call anywhere in your application, pass in the props to decide what it would display and how it should display.

You can take this even a step further by including the concept of variants. I would write more on this in a future part. But say for example we have a “ManagedModal” component. We could easily design this is to look a certain way if we want to show the user a form, a warning message, a loading spinner, an error message or whatever we would like. This allows us to build our components(molecules) as robust as we can while ensuring that it is simple enough to be called anywhere in the application or organisation.

Organisms are made of molecules

Organisms combine molecules. Usually they would have some more functionality than molecules. We can see example of this in things like; carousels, drawers. For instance, you have a couple of cards, they contain images, text and buttons and those cards are displayed in a carousel that simply receives one card, and the data for each card. Loops over them and displays content. This way you don’t have to create a carousel every single time you need one. You just call carousel.

interface ICarousel {
    Component: React.ReactNode;
    data: Card[];
    hasControls?: boolean;
    hasIndicators?: boolean
}

const Carousel = ({Component, data, hasControls, hasIndicators}) => {
    return (
        <div>
            {hasControls && (
                <div onClick={() => moveLeft()}>
                    <Button icon={LeftArrowIcon} variant={'rounded'} />
                </div>
            )}
            <div>
                {data.map((item, idx) => {
                    <Component key={idx} />
                })}
            </div>
            {hasControls && (
                <div onclick={() => moveRight()}>
                    <Button icon={RightArrowIcon} variant={'rounded'} />
                </div>
            )}
            {hasIndicators && (
                <div>
                    {data.map((item, idx) => {
                        <div key={idx} id={item.id} />
                    })}
                </div>
            )}
        </div>
    );
};

export default Carousel;


// Usage
<Carousel data={cardData} Component={Carousel}  />
Enter fullscreen mode Exit fullscreen mode

Templates and Pages

Our pages are made of sections or layout. They basically guide how a page should look. Think about it like the skeleton that would hold the organisms in place and form the pages.

Templates alot of times may not contain any logic. They are just styled, fed data and present the data. This allows for uniformity when implementing design systems. Things like spacing, backgrounds, paddings are typically what makes a layout.

In the end of this can now be put together to our actual routes. The pages.

Applications built like this are scalable, manageable and robust. With extra tooling components can even be treated as packages, shared across different applications. Our code is readable and can be easily documented making it simple for tother developers to join in or make updates without breaking things.

This is how I build applications. Some might see it as unnecessary or may just have a different approach. As long as that’s what works best for your team and you stay productive with it. The rules are not really set in stone.

Top comments (0)