svelte-loadable-data
v0.0.1
Published
A package for easily creating and managing a central store in svelte for occasions where data is loaded asynchronously.
Readme
Svelte Loadable Data
A package for easily creating and managing a central store in svelte for occasions where data is loaded asynchronously. The package manages both the data and the load state, and is ideal for cases where the speed and reliability is unpredictable.
Initialising
Your data store must be initialised by specifying the names and types of each property. This is done with the initData
function. This function takes a single parameter, dataStructure which is an object specifying each property's type, and an optional
default value.
function initData( dataStructure )dataStructure takes the following form:
const dataStructure = {
//propety without specified initial value
propertyName: [propertyType],
//or propety with specified initial value
propertyName: [propertyType, initialValue],
}Types and Initial Values
Every type has a default initial value if you don't otherwise specify it. The following is a list of possible types and their initial values:
| Type | propertyType | Default initial value |
|-------| ------ | ----- |
| Number | "number" | 0 |
| BigInt | "bigInt" | 0n |
| Boolean | "boolean" | false |
| Array | "array" | [] |
| Object | "object" | {} |
resetData
You can reset the data to its initialised state at any time with resetData. This will set all properties to their
initial values, with the load state set to initial.
$data and $values
The central store can be read a number of ways, but it provides two stores, $data, and the derived store $values.
Their exact structure depends on how you initialise them, but each property corresponds to a property
in the dataStructure you initialised them with.
$values
$values is just an object with the current values, but contains no information about load state. So if you have
initialised your data store but not loaded any data, all the properties of $values will exist, but just be their
initial values. These properties will change in the event that $data is updated.
A variable _values, is also exported, which is just the object in $values, but not as a store.
$data
Each property of $data corresponds to a property in the dataStructure object you used to initialise the package.
However, each property is a Loadable object. This means it takes the following structure:
{
// the current value
value: current_value,
// the property's type as defined in `dataStructure`
type: type,
// the current load-state of the property
state: "initial" | "loading" | "loaded" | "error",
// four aliases, only one of them will be true at any given time, if the current load-state matches that property
initial: true | false,
loading: true | false,
loaded: true | false,
error: true | false,
}
//Note: the load-states are automatically managed by other functions of the package, not manually.Load States
As indicated above, every property in $data has an associated load state. The load state of each property is
automatically managed by other functions of the package.
The four load states are:
initial
The initial, default state of a property. This means that it has its initial value.
loading
A load function (loadData or loadDatas) is in the process of attempting to retrieve data for this property.
loaded
A load function has successfully been used to retrieve data for this property.
error
An error occurred while using a load function to retrieve data for this property.
Load Functions
There are two load functions which are used for externally loading data to update your data store. loadData for when
you are only loading a single property from an external call, or loadDatas if the external call will retreive
multiple properties at once.
loadData
loadData(propertyName, async ()=>{
// function that returns the new property
})To use loadData the first param is the property you want to load, the second is a function that returns the new value.
When called, this will flag the property as loading, and will then update to either loaded (with the new value set)
if the load function is successful, or error if it throws for some reason.
example:
// Load the value of someString
await loadData("someString", async()=>{
//someString will now be flagged as "loading"
//do some async stuff to fetch the value from elsewhere
const value = await some.async.thing();
// return it, and it will update someString, and flag it as loaded
return value;
});loadDatas
loadDatas([...propertyNames], async ()=>{
// function that returns the new properties
})To use loadDatas, the first param is an array of names of the properties you want to load, the second is a function
that returns the new values as an object (each key is the corresponding property). When called, this will flag all the
listed properties as loading, and will then update them to either loaded (with new value set) if the load function
is successful, or error if it throws for some reason.
example:
// Load the value of someString, someOtherString and someNumber
await loadDatas(["someString","someOtherString", "someNumber"], async()=>{
//someString, someOtherString and someNumber will now be flagged as "loading"
//do some async stuff to fetch the values from elsewhere
const values = await some.async.thing();
// return them, and it will update the properties, and flag them as loaded
return {
someString: values.something,
someOtherString: values.somethingElse,
someNumber: values.somethingNumerical,
};
});getData
You can also retrieve the value of any property with:
getData(propertyName)readObject
In special cases where the property is an object, you can use
readObject(propertyName,objectPropertyName)hasProperty
In special cases where the property is an object, you can check if it has a sub-property with
hasProperty(propertyName,objectPropertyName)isLoaded
isLoaded(propertyName)Returns true if the property is loaded.
Updating data
There are a number of ways to update data so that things change properly within their desired lifecycles. There are a
number of "safe" functions which will do the desired action if the property is loaded, but do nothing (ie, not
throw but not make any changes) if the state is otherwise.
safeUpdate
safeUpdate(propertyName, newValue);Just set the new value
safeIncrement and safeDecrement
safeIncrement(propertyName);
safeDecrement(propertyName);For numerical types (number and bigInt), increments or decrements the value by 1.
safePush and safeRemove
safePush(propertyName, value);
safeRemove(propertyName, value);For arrays, push an item, or find and remove an item by value.
safeSetObjProp and safeDeleteObjProp
safeSetObjProp(propertyName, objectPropertyName, value);If a property of your data store is an object, this can be used to set the value of one of it's sub-properties.
safeDeleteObjProp(propertyName, objectPropertyName);If a property of your data store is an object, this can be used to delete one of it's sub-properties.
setData
The setData function can be used to set the value of a property without regard for whether it is loaded.
setData(propertyName,value, _stateId = stateId, updateWritable = true)Note:
_stateId is an internally tracked value that ensures slow asynchronous calls do not interfere with the data store in
the event that it is re-initialised.
updateWritable is a bool, if false it will not update the store itself, just _data.
Forcing Load States
Caution: you probably don't wanna do this unless you really know what you're doing.
Forcefully set the load state of a property with:
setInitial(propertyName)
setLoading(propertyName)
setLoaded(propertyName)
setError(propertyName)This just changes their state flags and not the values.
Example
// Initialise the Data Store by specifying the strcture, the types (and optional initial value)
const structur= {
someString: ["string"],
someStringWithInitialValue: ["string","initial value of string"],
someNumber: ["number"],
someBigInt: ["bigInt"],
someBoolean: ["boolean"],
someArray: ["array"],
someObject: ["object"],
}
initData(structure);
// Load the value of just someString
await loadData("someString", async()=>{
const value = await some.async.thing();
return value;
});
// Load the values of both someNumber and someBigInt at the same time.
await loadDatas(["someNumber","someBigInt"], async()=>{
const {someNumber, someBigInt} = await some.async.thing2();
return {
someNumber,
someBigInt
}
});
// Listen to events and trigger updates based on that
somethingWithEventListeners.on("someEvent", (newBoolean, newBigInt)=>{
// Set new values
safeUpdate("soemeBoolean", newBoolean);
safeUpdate("someBigInt", newBigInt);
//Increment someNumber
safeIncrement("someNumber");
});
