svelte-loadable-data Svelte Themes

Svelte Loadable Data

A package for easily creating and managing a central store in svelte for occasions where data is loaded asynchronously.

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");
});



Top categories

Loading Svelte Themes