SOLID in React

Solid principles

Solid principles

I would like to recall the SOLID principles and consider how they can be applied in interface development using React components as an example.

S: Single Responsibility Principle (Single Responsibility Principle) Means that each class/function/component should perform only one specific task.

Using the example of a React component: The component that renders the user interface should not contain the authorization logic for that user.

O: Open-Closed Principle (Open-Closed Principle) Means that a class/function/component should be open for expansion, but closed for modification. So that they can be expanded with new functionality without changing the source code.

Using the example of a React component:

Open-Closed Principle

Open-Closed Principle

In the example above we have an abstract base button that we cannot change, but we can extend it by passing values ​​such as className, onClick And children

Another way to implement this principle in React is to use HOC (pronounced not as nose, but as hock) (Higher-Order Component) is a function that takes a component and returns a new component with added behavior or functionality. This is a great way to reuse logic across components.

Example of using HOC with a button component

Example of using HOC with a button component

L: LSP (Liskov Substitution Principle). This means that objects of base classes should be replaceable by objects of derived classes without changing the expected behavior of the program. That is, derived classes should be able to be used in places where the base class is used without any changes.

Using the example of a React component:

LSP

LSP

In the base class Payment we define the method processPaymentwhich will process the payment. This method should be implemented in subclasses.

Both subclasses (CreditCardPayment And PayPalPayment) implement the method processPaymenteach in its own way. But both classes retain contractdefined by the base class, and can be used interchangeably.

Function processOrder accepts object paymentMethodwhich is an instance of any class that inherits Paymentand calls the method processPayment. Thanks to the Liskov substitution principle, we can pass both CreditCardPaymentand PayPalPayment into function processOrderand it will process any type of payment correctly.

The same works with the example with buttons, each type of button that extended the basic one can be used instead of the basic one without any changes, accordingly the LSP principle is fulfilled.

I: ISP (Interface Segregation Principle) Means that classes/functions/components should not depend on interfaces that they do not need.

Using the example of a React component: The simplest explanation for violating this principle is to pass a huge object to a component and only use one of its fields.

Violation of the ISP principle

Violation of the ISP principle

In the example above, it is in the component UserName pass only the name field, not the entire object

Compliance with the ISP principle

Compliance with the ISP principle

D: DIP (Dependency Inversion Principle) Means that high-level modules should not depend on low-level modules.

Using the example of a React component: Let's consider such a component

Example of DIP Violation

Example of DIP Violation

We have a simple component with a button, which, when clicked, causes logging. In this example, the high-level component is the button, and the low-level component is the logger function (ConsoleLogger) its pressing. As we can see, the button directly depends on the implementation of this logger, and according to the principle, it should depend on abstractions. The problem is that if you have to use a different logging method, you will have to change the component code.

Let's look at a component that follows the DIP principle

A component that complies with the DIP principle

A component that complies with the DIP principle

We defined the interface of the logger function, created several concrete implementations of the logger that conform to the defined interface. Component UserService now accepts the logger via props, which allows us to easily change the implementation of the logger without changing the component code. Thanks to this, we can use UserService with any logger that implements the interface ILogger

Example of use

Example of use

Conclusion

So, despite the fact that SOLID principles were originally developed and applied for OOP development, it turns out that they can be quite successfully applied in functional programming when developing interfaces – cool

If you liked it, subscribe to the channel in tg, I will write interesting things there

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *