DEV Community

Cover image for Cleaner Code with LSP: Writing Reusable React Native Components
Ars Dev
Ars Dev

Posted on

Cleaner Code with LSP: Writing Reusable React Native Components

From the author of the Telegram channel REACT NATIVE HUB

Join a growing community of React Native Devs! 👆


When building scalable React Native apps, clean architecture matters. One of the key principles of clean code is the Liskov Substitution Principle (LSP)— often overlooked, but incredibly powerful for designing reusable, maintainable components.

Let’s break it down and see how LSP applies in React Native, especially when creating buttons, inputs, or any shared UI components.

What Is the Single Responsibility Principle?

  • Definition: Objects or components should be replaceable with instances of their subtypes without altering the correctness of the program.
  • In React Native: When creating components or extending them, ensure they can be used interchangeably without breaking the application.

Bad Example: Violating LSP in React Native

In this example, incorrect use of interface methods and not following the base interface for the same type of component violates the LSP principle.

// ❌ BAD EXAMPLE - Violating LSP
interface BadBaseButton {
  onPress: () => void;
  text: string;  // Restricts to string only
}

const BadBaseButton: React.FC<BadBaseButton> = ({ onPress, text }) => (
  return (
    <TouchableOpacity onPress={onPress}>
       <Text>{text}</Text>
     </TouchableOpacity>
  );
);

// Violates LSP by changing prop structure and behavior
interface BadPrimaryButton {
  label: string;  // Different prop name
  onAction: () => Promise<void>;  // Different type
}

const BadPrimaryButton: React.FC<BadPrimaryButton> = ({ label, onAction }) => {
  return (
    <TouchableOpacity onPress={onAction}>
      <Text>{label}</Text>
    </TouchableOpacity>
  );
};

// Usage shows incompatibility
const BadExample: React.FC = () => {
  const handleClick = () => console.log('clicked');

  return (
    <View>
      <BadBaseButton
        onClick={handleClick}
        text="Click me"
      />

      {/* Won't work! Different props and behavior */}
      <BadPrimaryButton
        label="Click me"
        onAction={async () => console.log('clicked')}
      />
    </View>
  );
};
Enter fullscreen mode Exit fullscreen mode

Following LSP

It helps to ensure base props are extended consistently, the same onClick type throughout, components are interchangeable & add features without breaking the base contract.

// ✅ GOOD EXAMPLE - Following LSP
interface GoodBaseButtonProps {
  onPress: () => void;
  children: React.ReactNode;
}

const GoodBaseButton: React.FC<GoodBaseButtonProps> = ({ onPress, children }) => (
  <TouchableOpacity onPress={onPress}>{children}</TouchableOpacity>
);

// Properly extends base props
interface GoodPrimaryButtonProps extends GoodBaseButtonProps {
  variant?: 'solid' | 'outline';  // Optional additional prop
}

const GoodPrimaryButton: React.FC<GoodPrimaryButtonProps> = ({
  onPress,
  children,
  variant = 'solid'
}) => {
  const bg = variant === 'solid' ? 'bg-blue-500' : 'border-blue-500';
  return (
    <TouchableOpacity onPress={onPress} style={{backgroundColor: bg}}>
      {children}
    </TouchableOpacity>
  );
};

// Usage shows compatibility
const GoodExample: React.FC = () => {
  const handleClick = () => console.log('clicked');

  return (
    <View>
      {/* Both components can use the same handler */}
      <GoodBaseButton onPress={handleClick}>
        Click me
      </GoodBaseButton>
      <GoodPrimaryButton onPress={handleClick} variant="solid">
        Click me
      </GoodPrimaryButton>
    </View>
  );
};
Enter fullscreen mode Exit fullscreen mode

Key Takeaways

  • LSP ensures that your components remain interchangeable.
  • In React Native, always extend base props when creating variants.
  • Avoid re-inventing props or behavior for components that serve the same role.
  • Following LSP leads to better code reuseless duplication, and easier maintenance.

About me: My name is Arsen, and I am a react native developer and owner of the TG channel 👇

🔗 Join TG community for React Native Devs: REACT NATIVE HUB

Top comments (0)