When it comes to developing robust and scalable web applications using Angular, understanding the concepts of stateful and stateless components is crucial. These two types of components play a vital role in managing data and orchestrating the application’s behavior. To harness the full potential of stateful and stateless components, it is highly recommended to hire Angular developers with expertise in component-based architecture.
By hiring an Angular developer, you can ensure that your application is designed and implemented with the appropriate balance of stateful and stateless components, maximizing performance and maintainability.
In this article, we will delve into the world of stateful and stateless components in Angular, exploring their definitions, differences, and best practices for implementation. So, let’s dive in and discover how these components can elevate your Angular development endeavors to new heights.
Stateful
When something is “stateful,” it refers to a focal point that keeps track of the state of the application or component in memory. It has the capacity to alter it as well. It is essentially a “living” item that is aware of state changes in the past, now, and possibly in the future.
Stateless
Something that is “stateless” determines its internal state but never modifies it directly. The result will always be the same when given the same inputs, allowing for perfect referential transparency. These are only passed on information, thus they are not really “alive.” This indicates that it is unaware of any changes to the past, present, or future states.
Components
We may start to apply these ideas to component paradigms when discussing stateful vs stateless web application development. So, what exactly is a component? Similar to JavaScript functions, a component is a standalone instance of behavior or functionality that enables us to categorize behavior into different categories.
Difference between stateful and stateless component
Stateful components can contain stateless components, which are simply JavaScript functions, while stateless components are detailed implementations of the component that can vary over time.
Stateful Components
A stateful component uses any stateless components we have available because it is the driver of what happens, similar to an impure JavaScript function.
The following are characteristics of a stateful component:
- Drives state changes through functions
- Provides data (i.e. from HTTP layers)
- Route resolves rather than service layer calls may be used to retrieve the first data
- Has living knowledge of the current state
- Is informed when anything needs to change by stateless components.
- Can communicate with dependencies outside the system (such as an HTTP layer)
- Renders stateless (or even stateful) child components, possibly inside of a single div wrapper for layout confinement.
Stateful todo component
In this article, we’ll develop a simple to-do application to illustrate these ideas, then compare it to stateless counterparts.
Let’s begin by rendering our base component:
import { Component } from ‘@angular/core’;
@Component({
selector: ‘my-app’,
template: `
<todos></todos>
`
})
export class AppComponent { }
We are rendering a <todos> component inside of this box. Let’s go on; this component will be stateful. We all know that we won’t be teaching how to create a to-do app, so instead we’ll examine how to apply stateful and stateless paradigms to Angular 2 components and take note of the concepts.
Now look into the <todos> component:
import { Component, OnInit } from ‘@angular/core’;
import { TodoService } from ‘./todo.service’;
@Component({
selector: ‘todos’,
template: `
<div>
<todo-form
(onAdd)=”addTodo($event)”>
</todo-form>
<todo-list
[todos]=”todos”
(onComplete)=”completeTodo($event)”
(onDelete)=”removeTodo($event)”>
</todo-list>
</div>
`
})
export class TodosComponent implements OnInit {
todos: any[];
constructor(private todoService: TodoService) {}
ngOnInit() {
this.todos = this.todoService.getTodos();
}
addTodo({label}) {
this.todos = [{label, id: this.todos.length + 1}, …this.todos];
}
completeTodo({todo}) {
this.todos = this.todos.map(
item => item.id === todo.id ? Object.assign({}, item, {complete: true}) : item
);
}
removeTodo({todo}) {
this.todos = this.todos.filter(({id}) => id !== todo.id);
}
}
In the above example, you can see that all we have is a div container wrapping two more child (stateless) components. Other than that, the template contains no further logic. No input is provided to the component, but it anticipates binding a onAdd output. The ‘todo-list’ component then gets two outputs (‘onComplete’ and ‘onDelete’), handing off the corresponding functions to their stateless equivalents, and the ‘todos’ data from the ‘[todos] input binding.
The remaining methods in the component class are what give the todo component its functionality. Each callback contains immutable operations, and each callback is exposed to a stateless component so that it can work with it. All that these features require is a signal that something has changed. Take note of the fact that the functions are only invoked from the stateless, child level.
Stateless Components
A stateless component gets data through property binding (which is analogous to function arguments) and emits changes through an event (equivalent to a return block).
What does this mean, then? According to the way function scope chains operate, stateless components are unaware of any aspect of the program of which they are a part. They may therefore be moved around extremely simply, tested easily, and reused.
The following are characteristics of a stateless component:
- Never request or fetch data
- Are passed through property binding
- Data emit through event callbacks
- Further stateless (or even stateful) components are produced.
- Able to store local UI state
- Are a little piece of a larger picture.
Stateless TodoList Components
Let’s examine the stateless component, which is a direct child of <todos>:
@Component({
selector: ‘todo-list’,
template: `
<ul>
<li *ngFor=”let todo of todos”>
<todo
[item]=”todo”
(onChange)=”onComplete.emit($event)”
(onRemove)=”onDelete.emit($event)”>
</todo>
</li>
</ul>
`
})
export class TodoListComponent {
@Input() todos;
@Output() onComplete = new EventEmitter();
@Output() onDelete = new EventEmitter();
}
You can see that our @Input and @Output are clearly stated here and that this component class has no other members. For each output, we actually create an EventEmitter instance before breaking it down into more stateless components. In this scenario, the single component will be responsible for rendering each to-do item in our collection. In order to establish a simple chain, we also delegate the onComplete and onDelete methods, both of which are bound to the parent. We’ll have a look inside before finishing:
import { EventEmitter, Component, Input, Output } from ‘@angular/core’;
import { EventEmitter, Component, Input, Output } from ‘@angular/core’;
@Component({
selector: ‘todo’,
styles: [`
.complete { text-decoration: line-through; }
`],
template: `
<div>
<span [ngClass]=”{ complete: item.complete }”>{{ item.label }}</span>
<button
type=”button”
(click)=”onChange.emit({ todo: item });”>Done</button>
<button
type=”button”
(click)=”onRemove.emit({ todo: item });”>Delete</button>
</div>
`
})
export class TodoComponent {
@Input() item;
@Output() onChange = new EventEmitter();
@Output() onRemove = new EventEmitter();
}
Some of the inputs and outputs can send event data to the parent and then back up (if needed). The Angular 2 components listed above are all stateless. While receiving data via property bindings and emitting changes via event callbacks, they are unaware of their surroundings.
Conclusion
In this article, we have seen the stateful and stateless components of angular (hire Angular developers) and explain the concept with examples. We have seen that Stateful components can contain stateless components, which are simply JavaScript functions, while stateless components are detailed implementations of the component that can vary over time.