Search code examples
angularfrontendpersistencefront-end-optimization

Angular Architecture: How to handle state persistence with multiple HTTP Services?


I was wondering how you should structure an app which makes calls to a backend.

Wrapping HTTP calls in a service seems like a natural way to do things, but how / where do you keep the data for consistency? E.g. I have a component which displays some kind of Todo list, which is retrieved from the backend OnInit. Now when routing away from this component and routing back again all its data is reset. Of course, you could call the backend again, but wouldn't it be more beneficial to keep the data in some kind of service (even the HTTP service) for further use?

To further clarify:

class Service {

    storedData: number[] = []
    allObjects: BehaviorSubject<any> = new BehaviorSubject()

    ...


    getObj(id) {
        if (!this.storedData.includes(id)) {
            this.getDataFromServer(id)
        }
        return this.allObjects.pipe(
            map(objects => objects.find(obj => obj.id === id)),
            filter(obj  => obj && true)
        )
    }

    getDataFromServer(id) {
        return this.http.get(id).pipe(
            tap(obj => {
                this.storedData.push(id)
                this.allObjects.put(id, obj)
            })
        )
    }
}

Would this be a viable approach or are there other ways of handling such situations?

Furthermore, what would be the best way to go for using an object which needs multiple services to fill all its fields. (Obj: {a: number, b: number}, a is retrieved by AService and b by BService ).

Where would you store these objects (Injecting AService in BService and storing it in BService / injecting both into a third service which provides the data to requesting components)?

And what would be the best way of storing it?


Solution

  • Victor Savkin, former core Angular team member at Google who built the dependency injection, change detection, forms, and router modules, wrote an excellent article on Managing State in Angular Applications.

    He identified six common types of states for web applications:

    • Server state
    • Persistent state
    • The URL and router state
    • Client state
    • Transient client state
    • Local UI state

    Key Points

    • Server state is stored on the server and is provided, for example, via a REST endpoint
    • Persistent state is a subset of the server state stored on the client, in memory
    • Client state (such as filters used to create a list of items) is not stored on the server
    • RECOMMENDATION: It’s a good practice to reflect both the persistent and client state in the URL.

    This means that a component would update the URL parameters to reflect the persistent state (i.e. server state that is being cached on the client in memory) as well as client state, such as selected filters. URL parameters may be added for each service for which state is being persisted.

    The persistent state is stored in Angular services, where there would often be one service per functional unit, such as a Todo List service, a User service, and a logging service. Each of these services would handle state persistence behind the scenes. For example, when requesting data, the service would first check to see if the data had already been fetched from the server, and only if the data were missing, make an HTTP call.

    Since services are long lived, the data may persist throughout the duration of the user session.