State
A State
represents a piece of Information that we need to remember globally at a later point in time.
While offering a toolkit to use and mutate this piece of Information.
States are the foundation of AgileTs. Almost everything depends on States or extends its functionalities.
For example, a Collection is a dynamic set of States.
All you need to instantiate a State, is to call createState()
and specify an initial value.
// String State
const NAME = createState("Jeff");
// Number State
const AGE = createState(18);
// Array State
const SPECIAL_POWERS = createState(['water', 'dirt']);
// Nested State
const FRIENDS = createState({friendA: FRIEND_STATE_A, friendB: FRIEND_STATE_B});
// A light alternative to 'createState()' without bells and whistles like 'undo()', 'persist()', ...
const USER = createLightState({id: 10, name: 'jeff'})
We can create as many States as we need and bind them flexible to any UI-Component. Now that we have instantiated some States, we can dynamically and easily manipulate their value.
// Update the State value to 'Frank'
NAME.set("Frank");
// Undo latest State value change (-> value is now "Jeff" again)
NAME.undo();
// Merge 'friendC' into the FIRENDS State value object
FRIENDS.patch({friendC: FIREND_STATE_C});
// Permanently store the State value in an external Storage
NAME.persist();
// Check if the State value is equal to '['water', 'dirt']'
SPECIAL_POWERS.is(['water', 'dirt']); // Returns true
Want to learn more about the State's specific methods? Check out the State Methods documentation. Most methods we use to modify, mutate and access the State are chainable.
MY_STATE.undo().set("Hello Hell").watch(() => {}).reset().invert().persist().type(String);
🔨 Use case
We might use a State to remember the active theme of our application,
or the userId
of the current logged-in user.
const THEME_TYPE = createState("dark");
// <- toggled theme switch
THEME_TYPE.set("light");
In the above example, we create a THEME_TYPE
State with the initial value "dark".
After toggling the theme switch, we update the THEME_TYPE
to "light".
⛳️ Sandbox
Test the State yourself. It's only one click away. Just select your preferred Framework below.
👟 Light State
The Light State
is a lightweight alternative to the Enhanced State
,
which is referred as the 'normal' State in this documentation.
It is the State in its rawest and lightest form.
Thus, it is recommended when no additional functionalities
like persist()
, watch()
, undo()
, .. are required.
new State(agileInstance, initialValue, config);
// or
createLightState(initialValue, config);
Methods contained in the Light State
setKey()
set()
ingest()
addSideEffect()
removeSideEffect()
hasSideEffect()
🏋️ Enhanced State
What we refer as a 'normal' State in this documentation is the Enhanced State
.
Actually the Enhanced State
is an extension of the Light State
(normal State)
with many additional features.
Since the Enhanced State
is the most commonly used type of State,
the createState()
method creates an Enhanced State
.
new EnhancedState(agileInstance, initialValue, config);
// or
createState(initialValue, config);
// or
createEnhancedState(initialValue, config);
However, since the Enhanced State
is bloated with features,
it requires a larger bundle size than the Light State
.
📭 Props
// Enhanced State
new EnhancedState(agileInstance, initialValue, config);
// or
createState(initialValue, config);
// or
createEnhancedState(initialValue, config);
// Light State
new State(agileInstance, initialValue, config);
// or
createLightState(initialValue, config);
initialValue
The first value
assigned to the State.
const MY_STATE = createState("hello there");
MY_STATE.value; // Returns 'hello there'
Later we can access the initial value with the initialStateValue
property.
MY_STATE.initialStateValue; // Returns 'hello there'
config
Beside the initial value a State
takes an optional configuration object.
createState("myInitialValue", {
key: "myKey",
dependents: [MY_STATE_2]
});
Here is a Typescript Interface for quick reference. However, each property is explained in more detail below.
export interface StateConfigInterface {
key?: StateKey;
dependents?: Array<Observer>;
isPlaceholder?: boolean;
}
key
The optional property key/name
should be a unique string/number
to identify the State later.
createState("myInitialValue", {
key: "myKey"
});
We recommend giving each State a unique key
since it has only advantages:
- helps us during debug sessions
- makes it easier to identify the State
- no need for separate persist Key
Type | Default | Required |
---|---|---|
string \| number | undefined | No |
dependents
warning
This property is mainly thought for the internal use.
Specifies which States depend on this State.
createState("myInitialValue", {
dependents: [MY_STATE_2]
});
So if this State mutes and is ingested into the runtime
,
the depending States are ingested into the runtime
too.
Type | Default | Required |
---|---|---|
Array<Observer> | [] | No |
isPlaceholder
warning
This property is mainly thought for the internal use.
Defines whether the State is a placeholder
.
const MY_STATE = createState("myInitialValue", {
isPlaceholder: true
});
MY_STATE.exists(); // false
States are, for example, placeholder
when AgileTs needs to hold a reference to them,
even though they aren't instantiated yet.
Type | Default | Required |
---|---|---|
boolean | false | No |
🟦 Typescript
The State Class
is almost 100% typesafe and takes an optional generic type for type safety of its value
.
const MY_STATE = createState<string>("Hello World");
MY_STATE.set(1); // Error
MY_STATE.set("hello space"); // Success