State and Persistence

The framework comes with a state and persistence layer that lives on the ApplicationManager. Almost all applications are going to require some state in order to operate, so this tool allows you to store and re-use state in a consistent manner.

Note

State management is a hard subject. Here we detail how to use state but not necessarily the best methods for doing so in your application. You need to think about how best to use state on a per application basis.

Another Note

We are transitioning to using Redux as a state manageemnt tool / process. Everything in this article will still be 100% possible after the transition, but it's mostly being documented to support older apps that haven't transitioned over.

The Store

The store is what we refer to as the place for managing state. This is located in client/store/store.ts. By default, there is only one method available:

protected _generateInitialState(): MyAppState {

    return {

        _id: this.name,
        _rev: "",
        messageQueue: []
    };
}

This does exactly what it says on the tin. You set the initial state of your application here. Usually, this isn't so large because you'll probably be fetching a lot of state from API's, etc, but for anything that can be hardcoded into the app - this is where you do it.

State Property

The store has a property called state. This is an in memory version of your entire application state. Therefore, reading from the store is very fast. When your application boots up, this property is set automatically so your state is available very early in the app lifecycle.

The state is type safe too. The _generateInitialState() function is typed to return a MyAppState object. This can be anything you want and you're free to extend this inside: client/store/state.ts.

Binding your Store

Note: This is usually taken care of for you and you do not need to do this yourself.

You need to bind your store to the app manager. This easily done inside the root index.ts file. There is a const for your application classes like so:

const myAppCustomClasses: AppClasses = {

    store: MyAppStore
};

This is then passed into the app manager initialisation like so:

window.MyAppManager = new MyAppManager("body", "view-login", appConfig, MyAppViews, myAppCustomClasses, myAppHandlers);

Persistence

By default, the store is persisted and saved. This is done using PouchDb. It is up to the application developer to decide when writes to the PouchDb happen, as we'll detail below. _generateInitialState() is only called when the store cannot find a suitable PouchDb to load data from.

Getting and Setting

Getting and setting state is relatively easy.

Getting

This is typical example of getting some state:

this.manager.store.getSomeState();

This can be called from lots of places, including components. The above would resolve to a method inside your client/store/store.ts file, e.g:

public getSomeState(): MyState {

    return this.state.myState;
}

It's up to you to decide how to define your getters and any logic which may be required of them (for example, sorting or filtering).

Setting

Setting is also very similar to getting:

public async setSomeState(myState: string): void {

    this.state.myState = myState;
    return await this._saveToPersistent();
}

This is then called like:

this.manager.store.state("Let's set some state");

// OR

await this.manager.store.state("Let's set some state");

You simply create another method in the store that is responsible for setting state. Most setting functions should be async because you're very likely to also want to save the state to the persistence layer (PouchDb) so the data isn't lost. Calling: await this._saveToPersistent(); ensures that the current in memory state object is saved.

Why Getters & Setters?

Chances are that more than one thing is going to want to use a single piece of state. This is especially true for job lists, contact lists, etc.

Using the getter / setter pattern allows all the different things that need access to state to get / set in a very similar way. On larger applications with big state trees this can be helpful - especially if you end up changing the underlying state object.

There are some downsides though. The store can become quite large with a lot of boiler plate code. This is a consequence of writing code like this and is one of the reasons we are looking to use Redux to take over state management.

results matching ""

    No results matching ""