DEV Community

Cover image for Beyond Tradition: Innovating with Component-Driven Development
Lakshmanan Arumugam
Lakshmanan Arumugam

Posted on • Originally published at lakshmananarumugam.com

Beyond Tradition: Innovating with Component-Driven Development

Component-driven development(CDD) in React is an approach to building user interfaces where the development process revolves around creating and assembling reusable components. These components are self-contained, modular building blocks that encapsulate specific functionality and appearance. CDD encourages a more efficient and maintainable development process by promoting code reusability and ease of testing.

Here are the key principles and benefits of component-driven development in React:

Modularity: Components in CDD are designed to be independent and reusable, making it easier to manage and maintain your codebase. Each component should have a clear purpose and should be self-sufficient.

Isolation: Components should be isolated from one another, meaning they should not directly depend on or interfere with each other's logic. This isolation allows for better testing and easier debugging.

Testing: Because components are isolated, testing becomes more straightforward. You can focus on testing each component in isolation, ensuring that they work correctly without having to deal with complex interactions.

Reusability: Once you've built a set of reusable components, you can leverage them throughout your application, reducing redundant code and development time.

Storybook: A popular tool for implementing CDD in React is Storybook. Storybook provides a development environment where you can visually see and interact with each component in isolation. It facilitates rapid iteration and design of components without the need for a complete application.

Collaboration: CDD can improve collaboration between designers, developers, and other stakeholders. It allows designers to create and showcase their designs in Storybook, and developers can then build the components based on the provided design specifications.

Documentation: Storybook can also serve as living documentation for your components, making it easier for developers to understand and use them correctly.

Component-driven development empowers developers to build applications like assembling LEGO blocks. By breaking down complex systems into modular and reusable components, we create maintainable, scalable, and delightful user experiences.

Here's a basic workflow for component-driven development in React using Storybook:

Create Stories: Create "stories" in Storybook, which represent different states and use cases of your components.

Build Components: Develop your React components in isolation, ensuring they are reusable and self-contained.

Visualize Components: View each component in Storybook's UI, interact with them, and test different scenarios.

Iterate and Refine: Make design and functionality improvements based on feedback, and iterate until the components meet the desired requirements.

Integrate into App: Finally, integrate the developed components into your React application to build the complete user interface.

Component-driven development is an effective approach to building scalable and maintainable React applications.

In React with TypeScript, we can define different types of components using interfaces and React's TypeScript types. Let's explore some common component types with examples for each:

1.Functional Component:

Functional components are basic building blocks in React. In TypeScript, we can define the type for the component props using an interface.

import React from 'react';

// Define the props interface
interface MyComponentProps {
  name: string;
  age: number;
}

const MyComponent: React.FC<MyComponentProps> = ({ name, age }) => {
  return (
    <div>
      <p>Name: {name}</p>
      <p>Age: {age}</p>
    </div>
  );
};

export default MyComponent;
Enter fullscreen mode Exit fullscreen mode

2. Class Component:

Class components are the traditional way of defining components in React. We can define the props and state types using interfaces.

import React, { Component } from 'react';

// Define the props interface
interface MyClassComponentProps {
  message: string;
}

// Define the state interface
interface MyClassComponentState {
  count: number;
}

class MyClassComponent extends Component<MyClassComponentProps, MyClassComponentState> {
  constructor(props: MyClassComponentProps) {
    super(props);
    this.state = {
      count: 0,
    };
  }

  render() {
    const { message } = this.props;
    const { count } = this.state;
    return (
      <div>
        <p>{message}</p>
        <p>Count: {count}</p>
      </div>
    );
  }
}

export default MyClassComponent;

Enter fullscreen mode Exit fullscreen mode

3. Functional Component with Hooks:

With React hooks, functional components can use state and other React features without using class components. We can define the types for props using interfaces.

import React, { useState } from 'react';

// Define the props interface
interface HooksComponentProps {
  initialCount: number;
}

const HooksComponent: React.FC<HooksComponentProps> = ({ initialCount }) => {
  const [count, setCount] = useState(initialCount);

  const increment = () => {
    setCount((prevCount) => prevCount + 1);
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
    </div>
  );
};

export default HooksComponent;
Enter fullscreen mode Exit fullscreen mode

4. Stateless/Functional Component with Conditional Rendering:

A stateless/functional component with conditional rendering is a simple React function component that displays different content based on conditions. It doesn't maintain its own state and relies on props to determine what to render.

import React from 'react';

interface GreetingProps {
  name: string;
  isLoggedIn: boolean;
}

const Greeting: React.FC<GreetingProps> = ({ name, isLoggedIn }) => {
  return (
    <div>
      {isLoggedIn ? <p>Hello, {name}!</p> : <p>Please log in.</p>}
    </div>
  );
};

export default Greeting;
Enter fullscreen mode Exit fullscreen mode

5. Container Component:

A Container Component, also known as a smart component, is a type of React component responsible for managing the business logic, data-fetching, and state management for its child components. It encapsulates the complex logic and communicates with external data sources or stores, passing down the required data and behavior as props to presentational (dumb) components. Container components help in separating concerns, promoting code reusability, and improving overall application maintainability.

import React, { useEffect, useState } from 'react';
import UserList from './UserList';

interface User {
  id: number;
  name: string;
}

const UserContainer: React.FC = () => {
  const [users, setUsers] = useState<User[]>([]);

  useEffect(() => {
    // Fetch user data from API
    // For demonstration, using a mock user data
    const mockUsers: User[] = [
      { id: 1, name: 'Alice' },
      { id: 2, name: 'Bob' },
      { id: 3, name: 'Charlie' },
    ];
    setUsers(mockUsers);
  }, []);

  return <UserList users={users} />;
};

export default UserContainer;
Enter fullscreen mode Exit fullscreen mode

6. Higher-Order Component (HOC):

A Higher-Order Component (HOC) is a function in React that takes a component and returns an enhanced version of that component with additional functionality. It's a powerful pattern for code reuse and adding behaviors to components.

import React from 'react';

interface WithLoggerProps {
  message: string;
}

const withLogger = <P extends object>(
  WrappedComponent: React.ComponentType<P>
) => {
  return class WithLogger extends React.Component<P & WithLoggerProps> {
    componentDidMount() {
      console.log(`Logged message: ${this.props.message}`);
    }

    render() {
      // Omit the `message` prop from the enhanced component
      const { message, ...props } = this.props as WithLoggerProps;
      return <WrappedComponent {...props as P} />;
    }
  };
};

interface MyComponentProps {
  name: string;
}

const MyComponent: React.FC<MyComponentProps> = ({ name }) => {
  return <div>Hello, {name}!</div>;
};

export default withLogger(MyComponent);

Enter fullscreen mode Exit fullscreen mode

7. Hooks-Based Component with Context:

A Hooks-Based Component with Context is a React functional component that uses hooks and context to share data efficiently across the component tree, avoiding prop drilling.

import React, { useContext } from 'react';

// Create a context
interface ThemeContextProps {
  theme: 'light' | 'dark';
  toggleTheme: () => void;
}

const ThemeContext = React.createContext<ThemeContextProps>({
  theme: 'light',
  toggleTheme: () => {},
});

// Use the context in a functional component
const ThemeToggler: React.FC = () => {
  const { theme, toggleTheme } = useContext(ThemeContext);

  return (
    <div>
      <button onClick={toggleTheme}>
        Toggle Theme (Current Theme: {theme})
      </button>
    </div>
  );
};

export default ThemeToggler;
Enter fullscreen mode Exit fullscreen mode

8. UI component (Important)

A UI component is a self-contained, reusable building block that represents a specific visual element or user interface element in a software application. Here's an example of a simple UI component in React:

import React from 'react';

const Button = ({ label, onClick }) => {
  return (
    <button onClick={onClick}>
      {label}
    </button>
  );
};

export default Button;

//Using in application

<Button label="Hit me" onClick={() => console.log("Hello world") }/>

Enter fullscreen mode Exit fullscreen mode

Component-Driven Development (CDD) is a powerful approach that promotes code reusability, modularity, and collaboration. By breaking complex user interfaces into reusable components, CDD enables rapid development, efficient testing, and consistent user experiences across the application. It enhances maintainability and scalability, making it a valuable methodology for modern web development.

Thanks for reading and cheers 🥂

Top comments (4)

Collapse
 
abidullah786 profile image
ABIDULLAH786

Hello, Lakshmanan Arumugam!

Welcome to the Dev.to community! 🎉 We are thrilled to have you join us and become a part of this vibrant and inclusive platform for developers, like yourself, to share and learn from each other.

Feel free to explore the vast array of articles, tutorials, and discussions contributed by fellow developers from around the world. Whether you are a seasoned coder or just starting your journey, Dev.to offers a welcoming space to showcase your expertise, ask questions, and connect with like-minded individuals.

As a moderator, I am here to assist you in any way I can. If you have any questions about the platform, guidelines, or anything else, please don't hesitate to reach out. Your valuable contributions to the community are appreciated, and we encourage you to share your knowledge, experiences, and insights with us.

Your article is incredibly well-written and insightful. I love how you explained complex concepts in a simple and engaging manner, making it easy for readers to grasp the key points. The examples you provided were spot-on, and your code snippets were clear.

We hope you have a fantastic experience on Dev.to, and we look forward to seeing your engaging posts and contributions!

Happy coding! 🚀

Best regards,
[Your Name]
Dev.to Moderator

Collapse
 
lakshmananarumugam profile image
Lakshmanan Arumugam

Thanks for your support. if i need anything i will reach out you guys

Collapse
 
joevaugh4n profile image
Joe

Hey Lakshmanan! I'm one of the Storybook maintainers. Just to say thanks for sharing Storybook in this piece – this is a brilliant write-up and we always love reading people championing component-driven design!

If you'd like an idea for another article, we actually just shipped Storybook 7.1 which has some new features to help users getting started with CDD. Would love to hear your thoughts on it!

Collapse
 
lakshmananarumugam profile image
Lakshmanan Arumugam

Will see the changes @joevaugh4n