dojo dragon main logo

Advanced store operations

Dojo Stores use operations to make changes to the underlying state of an application. The operations are designed in a way to help simplify common interactions with the store, so, for example, operations will automatically create the underlying structure necessary to support an add or replace operation.

To perform a deep add in an uninitialized store:

import Store from '@dojo/framework/stores/Store';
import { add } from '@dojo/framework/stores/state/operations';

const store = new Store<State>();
const { at, path, apply } = store;
const user = { id: '0', name: 'Paul' };

apply([add(at(path('users', 'list'), 10), user)]);

Which gives a result of:

{
    "users": {
        "list": [
            {
                "id": "0",
                "name": "Paul"
            }
        ]
    }
}

Even though state has not been initialized, Dojo is able to create the underlying hierarchy based on the provided path. This operation is safe because of the type safety that TypeScript and Dojo Stores provide. This allows for users to work naturally with the State interface used by the store instead of needing to be concerned with the data explicitly held by the store.

When an explicit state is required, that information can get asserted by using a test operation or by getting the underlying data and validating it programmatically.

This example ensures that user always gets added to the end of the list as the last element by using a test operation to ensure initialization:

import Store from '@dojo/framework/stores/Store';
import { test } from '@dojo/framework/stores/state/operations';

const store = new Store<State>();
const { at, path, apply } = store;

apply([test(at(path('users', 'list', 'length'), 0))]);

This example ensures that user is always added to the end of the list as the last element by programmatic introspection:

import Store from '@dojo/framework/stores/Store';
import { add, test } from '@dojo/framework/stores/state/operations';

const store = new Store<State>();
const { get, at, path, apply } = store;
const user = { id: '0', name: 'Paul' };
const pos = get(path('users', 'list', 'length')) || 0;
apply([
    add(at(path('users', 'list'), pos), user),
    test(at(path('users', 'list'), pos), user),
    test(path('users', 'list', 'length'), pos + 1)
]);

Access to state root is not permitted and will throw an error, for example when trying to perform get(path('/')). This restriction also applies to operations; it is not possible to create an operation that will update the state root. Best practices with @dojo/framework/stores encourage accessing the smallest necessary part of the store.