3

How To Build Better React Components in 2024?

 9 months ago
source link: https://blog.bitsrc.io/how-to-build-better-react-components-in-2024-2d930b1f30b1
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

How To Build Better React Components in 2024?

4 Patterns for Extensible and Reusable React Components

1*CVoKGjS-r8O2xPUeYKf32g.png

Extensible and reusable components are fundamental in modern React development, especially when aiming for efficient and scalable user interface design.

This ensure that your React components are easy to maintain and are versatile enough to be adapted across various applications.

The key to their success lies in their straightforward design and adaptability, which enables them to fit seamlessly into different contexts within an application or across various projects. By focusing on extensibility and reusability, you can create components that serve various purposes while maintaining a consistent design and functionality.

So, this article aims on achieving exactly that! We will take a look at how we can implement highly scalable and reusable React components that you can use across multiple applications! But, to do so, we will be relying on a Build Engine — Bit.

Bit lets you design and build anything in reusable independent components. Not only that, but it offers a CI server — Ripple CI thats capable of propagating changes across components trees to maintain consistency.

At the end of this blog, you will be gain a practical perspective on how extensible and reusable patterns can be effectively implemented, enhancing collaboration and uniformity in UI development across diverse team projects.

Practise 01: Building Base UI Components with Bit: A Closer Look

What exactly is a Base UI Component?

A Base UI Component is a bare minimum component that has a pre-defined behavior that can be customized by the consumer. For example, take a look at this Basic UI Collection that I’ve hosted on Bit Cloud.

1*Cwls2PrFh4jt7zmnRU9jIw.png
Figure: The Basic UI Component Collection

It has everything that you need, in bare-bones to let you get started with your next React application with minimum effort.

Every component that we’ll be using in this demo is located under the Scopebitdesign.basic-react.

This scope acts as a centralized hub, providing various foundational components that are independent yet easily accessible for teams working on React projects. It facilitates a structured yet flexible approach, allowing teams to efficiently access, use, and individually customize these essential UI components, ensuring consistency and adaptability in their development workflows.

In our bitdesign.basic-react Bit scope, we'll explore key components that demonstrate the principles of extensible and reusable design. These components are:

  • A Theme Component: This component establishes the design language and tokens for the Acme brand, ensuring consistency in styling across all UI elements.
  • A Button Component: A fundamental UI component designed for buttons, aligning with the Acme theme's guidelines.
  • An Environment Component: An environment component that forms the development setting for all base components. For example, it integrates the ACME theme, enabling each component to be developed and previewed with appropriate styling.

To build better components, you need traceability

You’re right. You need to keep track of what other components use a particular component. This can help track breaking changes, and highlight areas of impact right out of the gate!

With Bit, you can use its dependency graph to understand how your components interact. It illustrates the interconnectedness of components.

For example, in our scope,the ACME theme’s updates directly impact related components like button and the acme-react-env. This graph ensures that changes in design or functionality are uniformly applied across all dependent components, as shown below:

1*QoIwj4UmZw5irJGfaTMWJw.png
Figure: Observing the Dependency Tree

This dependency graph is particularly beneficial in large-scale projects involving multiple teams. It aids in efficient change management, guaranteeing that updates within a scope are in sync and align with the broader organizational standards. By utilizing this feature, teams can maintain a cohesive and unified design language across different project segments.

Practise 02: Exposing Component APIs for Enhanced Functionality and Type Safety

Exporting a component’s API and its types enhances its functionality and ensuring type safety, particularly when different teams are involved.

Here’s an example of how the API and types for the Button component are exposed in bitdesign.basic-react/buttons/button:

// index.ts in bitdesign.basic-react/buttons/button
export { Button } from './button';
export type { ButtonProps } from './button';

When another team needs to extend this Button component, they can import its type and adapt it according to their specific requirements:

import React from 'react';
import { ButtonProps as BaseButtonProps, Button as BaseButton } from '@bit/bitdesign.basic-react.buttons.button';

export type ExtendedButtonProps = BaseButtonProps & {
// Additional props specific to the extended button
};

export const ExtendedButton = ({ children, ...rest }: ExtendedButtonProps) => {
// Implementation that utilizes the base Button component
return <BaseButton {...rest}>{children}</BaseButton>;
};

This approach of extending types ensures that there’s a consistent interface across different implementations. It makes the most of TypeScript’s capabilities for improved compile-time checks and overall developer experience.

Moreover, thanks to Bit’s dependency graph, every time the API in the base component is updated, components that extend or use it will also be updated. This automatic synchronization ensures that all teams are working with the most current version of the component, maintaining consistency and reliability across the project. This feature is particularly valuable in complex projects where multiple teams rely on shared components, as it keeps everyone aligned with the latest changes and improvements.

Practise 03: Theming for Style Consistency with the Theme Component

To maintain a consistent look and feel, base components are designed to be themeable.

This is achieved by utilizing a theme component, like bitdesign.basic-react/acme-theme, which holds all design tokens as CSS variables. This setup allows for easy overrides and ensures that components adhere to a unified design language.

For example, the Button component might use the theme as follow

import { useTheme } from '@bitdesign.basic-react.acme-theme';

const Button = ({ className, children }) => {
const { primaryColor } = useTheme();
const style = { background: primaryColor };
return <button style={style} className={className}>{children}</button>;
};

The use of a theme component simplifies managing and applying design changes across all components, enhancing maintainability and scalability.

Practise 04: Enhancing Customizability and Extendability

Enhancing Customizability with ClassName Prop

The inclusion of a className prop in a component's API enhances its customizability. This feature allows users of the component to apply their own styles, making the component adaptable to different design contexts. Here’s an implementation example:

import classNames from 'classnames';
import styles from './button.module.scss';

export type ButtonProps = {
children?: ReactNode;
className?: string;
} & React.HTMLAttributes<HTMLButtonElement>;
export function Button({ className, children, ...rest }: ButtonProps) {
return (
<button {...rest} className={classNames(styles.button, className)}>
{children}
</button>
);
};

In this snippet, the className prop works alongside the classNames utility. The styles.button provides the default styling defined in the component's stylesheet. The className prop, however, is for additional style — adding or overriding the orginal base style, by the consumer of the component.

The sequence in which these class names are applied is significant. Placing the className prop last in the classNames function ensures that any styles provided by this prop override the default styles in case of any conflicts. This design allows users to maintain the fundamental design and functionality of the component while customizing its appearance to suit specific requirements. It strikes a balance between maintaining a consistent base style and offering flexibility for customization, a vital aspect of creating reusable, adaptable components.

Extendability with Spread Operator

The spread operator (...rest) is a powerful feature in React that enhances the extendability of components by passing all additional props to them. This ensures the component inherits all native properties of the underlying HTML element, making it more flexible and adaptable for different use cases.

Here’s an example of how to apply this pattern in thebitdesign.basic-react/typorgraphy/text component:

import React, { HTMLAttributes, ReactNode } from 'react';

type TextElements = 'span' | 'p';

export type TextProps = {
children?: ReactNode;
className?: string;
textElement?: TextElements;
} & HTMLAttributes<HTMLSpanElement | HTMLParagraphElement>;
export function Text({ children, className, textElement = 'p', ...rest }: TextProps) {
const TextElement = textElement;
return (
<TextElement {...rest} className={className}>
{children}
</TextElement>
);
}

In this Text component, the spread operator is used to pass any additional HTML attributes to the rendered text element. This means you can use the Text component like any standard HTML paragraph (p) or span (span) element, applying native HTML attributes directly:

<Text id="unique-text-id" style={{ color: 'blue' }}>Sample Text</Text>

Here, id and style are additional attributes passed to the Text component. They are applied directly to the underlying HTML element (p or span), demonstrating the component's extendability. This approach ensures that the Text component is not only customizable but also fully functional and compliant with standard HTML behavior, allowing for a wide range of applications in different contexts.


Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK