The Power Of OOP Components, Done Right 4-8-2025

The Limitations of Functional Components

Functional declarative components are one of the greatest milestones in the evolution of UI development. They transitioned us from the over-engineered MVC architecture and manual DOM updates to the declarative, reactive components we know and love. However, they have their limitations.

The declarative nature of today's frameworks simplified DOM construction and updates, but at the same time, it took away DOM ownership and restricted our ability to manipulate the DOM under its control.

The unpredictable nature of framework internals, a consequence of declarativity, while being localized by fine-grained reactivity to specific elements, has constrained the ability to manipulate the DOM manually. At best, such manual changes will be overwritten.

Furthermore, because components are functions that return the structure, this approach prohibits starting from existing DOM elements and complicates the manipulation of the component's DOM after removal.

In addition, functions don't scale. The factory paradigm is designed for small, simple components with minimal state and reactivity, not for complex, large components that encapsulate complicated logic and enormous state.

Moreover, the abstracted nature of functional components limits their ability to interact with the outside world, forcing their declaration inside the component since they are not normal values, which increases logic complexity within components.

When you call them, they return the structure, not the component itself. Our components have lost their identity.

The OOP Components Were Not Bad

Object-oriented components, like any OOP technology, are not inherently bad. The culture and traditions associated with them are what made them feel that way. The issue with past frameworks was their focus on complex MVC patterns, not on the UI itself, and this was a problem of architecture, not of the object-oriented paradigm.

The real problem was the separation of data from the UI. What are the real benefits of separating concerns through countless classical MVx patterns when the data is already processed by the server? It just created countless useless concepts that should not have been used.

Moreover, these frameworks provided little, if any, templating. At a minimum, you would use jQuery for manual DOM manipulation or use a templating engine that provided minimal bindings, in contrast to the deep reactivity and expressive templating we have today.

In short, the issue was the focus on the complicated design patterns associated with classical OOP culture and the lack of declarative reactivity, which is not a problem with the OOP component itself. However, functional programming won because of its minimal nature at a time when we were tired of everything related to classical OOP.

And, as a surprising fact, the old view units were actually a render function wrapped in a class, a pattern that persisted in React with its class-based components before the evolution of hooks.

Contrary to what one might think, declarative reactivity is not limited to the functional paradigm. While a function's declarative nature makes it a good choice, it is a concept that can be adopted even in imperative programming, and it is absolutely able to thrive in OOP components.

About NeoComp Components

NeoComp is a concept framework that fuses declarative reactivity with object-oriented components, combining the simplicity of reactivity with the flexible power of OOP components, thereby creating flexible components for all use cases.

NeoComp components are ordinary object-oriented components that encapsulate their own logic and state. They feature declarative reactivity in their APIs, wrapping an element and binding via their states to the DOM through fine-grained reactivity.

Events call methods on the component, which then update the states that are bound to the DOM through bindings declared in templates.

The NeoComp approach tries to bridge the gap between these two worlds, offering simple yet powerful fine-grained reactivity while still having the organizational benefits of object-oriented components. This approach has had some very surprising outcomes.

The Surprising Advantages of OOP Components

Better Organization

One of the notable benefits of OOP is its inherent, organizable structure. In contrast to a functional component where a single function can quickly grow out of hand, you can split complex logic into multiple methods and interact with each other via shared state in fields. This makes object-oriented components a better choice for large, stateful components with complex logic.

First-Class Citizen Components

A key outcome of switching to OOP is that components become first-class citizens. Components in OOP have a tangible, accessible value, in contrast to the abstract nature of functional components. This completely simplifies interaction with the outside world and opens many new possibilities.

Interactions can happen from outside the component, not only from within, which reduces some logic complexity inside the components.

Components can also officially expose a public interface in a non-hacky way, allowing other components to interact with them, in contrast to functional components that are typically passed events as arguments and that's it.

Full Ownership of the DOM

NeoComp's goal is to give you, the developer, full control and ownership of the DOM. The components are designed to wrap elements and create new ones if not provided. This enables the wrapping of existing elements with their structures, not just children constructed at creation, which allows for more design patterns.

These components can also leave their elements after removal if requested, in contrast to functional components that always destroy them, allowing for removal animations and changing the components around an element.

NeoComp favors direct DOM manipulation when needed and provides utilities for simplifying the process, as well as countless utilities for avoiding the need for them.

And most crucially, NeoComp provides you with true ownership of the DOM. Its actions on the DOM are localized to specific elements and attributes defined in the template. You can safely interact with other elements. Moreover, because of the direct nature of the DOM bindings, you can move target elements around, even outside the component, or remove and restore them later while preserving the bindings.

Simplified Internals

Having an accessible value for components simplifies the internals a lot. Primarily, it removes the need for magic functions that work on the underlying internal component structures and have their constraints (which are the only solution for functional components).

In addition, it also simplifies template internals. Instead of having algorithms that detect the used states and functions in directives, the component's value can be passed instead, removing the need for these algorithms.

Unmatched Flexibility

NeoComp's primary goal is to be a flexible framework adaptable to all use cases. It achieves this by making its units very flexible and unrestrictive, giving the developer complete freedom.

NeoComp provides a robust toolset, supporting lazy loading, first-class asynchronous programming, fine-grained reactivity, independent context for state management, auto dependency management, and much more.

Components in NeoComp are anonymous by default. They are not fixed in a static hierarchy; they behave more like DOM nodes than components in other frameworks. You can move them around in the main hierarchy or between different ones, and remove them, then restore them later.

NeoComp exposes a broader API surface, and its internal mechanisms are dynamic. The definitions (state, effects, contexts, etc.) can be created and modified at any time, in any place, not only at initialization.

You can even have the logic directly in the DOM for small, hacky projects.

The Ending, But Not The End

In summary, NeoComp is a frontend framework that combines the simplicity and efficiency of fine-grained reactivity with the organizational power of object-oriented components. It is also flexible enough in design to power everything from the smallest components to the largest ones.

It is a case study showing that simplicity in directness outperforms simplicity in declarativeness. Simplicity is not in the API surface; it is in the implementation.

React showed the world the power of declarative, reactive UI, but it had its limitations. The rest of the world further enhanced it through optimization and refinement, to the point where we made it as efficient as manual DOM manipulation through fine-grained reactivity.

However, there were still issues with our approaches. The function paradigm is for the factory pattern—one-shot creation—not for components with a lifecycle, and absolutely not for components with complex behaviors. Declarativity is not meant only for functions; it can be integrated with OOP, the paradigm designed primarily for stateful entities.

Finally, the quest doesn't stop here. There remain patterns in the wild that are yet to be discovered. Furthermore, we have the milestone of moving React into the efficient reactivity paradigms, and with it, the vast majority of the modern web.

If you are interested in NeoComp's concepts and want to learn more about it and its inner workings, check its documentation and dive into its source code on its repo on GitHub, and don't forget it is just a concept.