Singles
Singles are perhaps the most versatile Module type that Providence provides. Singles allow you to represent an arbitrary data structure in your state manager without creating extra boilerplate for their maintenance.
Singles are commonly composed into Lists.
Single Controllers
As with all Providence modules, you will want to interact with Singles through their controllers.
To get a new single controller:
TypeScript
import {useSingle} from '@opencraft/providence/react/hooks'
// Declare a type in TypeScript to get typechecking for your single's data structure.
declare interface MyStructureType {
id: number,
name: string,
}
const MyComponent = () => {
controller = useSingle<MyStructureType>('currentItem', {endpoint: 'https://example.com/api/endpoint/'})
// ... The rest of your component code goes here!
}
JavaScript
import {useSingle} from '@opencraft/providence/react/hooks'
const MyComponent = () => {
controller = useSingle('currentItem', {endpoint: 'https://example.com/api/endpoint/'})
// ... The rest of your component code goes here!
}
TypeScript
// Coming once the Vuex module is completed.
JavaScript
// Coming once the Vuex module is completed.
Single Module Options
In most cases, you’ll only need to hand the retrieval function the endpoint
of the object you’re
retrieving, but you may also need to set a number of other attributes.
- class SingleModuleOptions()
The construction parameters are mostly state that the SingleModule will be initialized with. This contains both the data of both the singleton itself and meta information about its status and how it is to be managed.
interface
- SingleModuleOptions.attempted?
type: boolean
Indicates whether we have attempted to fetch the data from its endpoint before.
- SingleModuleOptions.deleted?
type: boolean
Indicates that the resource this single is tracking has been deleted.
- SingleModuleOptions.endpoint?
type: string
The URL for the endpoint this single tracks. You can set this to # if you’re only using this single for local state management. This will prevent the patchers from making bogus network requests.
- SingleModuleOptions.failed?
type: boolean
Indicates that our attempt to fetch the data has failed.
- SingleModuleOptions.fetching?
type: boolean
Indicates whether we are currently waiting on the data to load from its endpoint.
- SingleModuleOptions.params?
type: <TODO: other type>|QueryParams
The query string parameters used when performing network operations on the endpoint.
- SingleModuleOptions.persistent?
type: boolean
If set to true, the registry will not remove this module even if all listening components are removed.
- SingleModuleOptions.ready?
type: boolean
Indicates that we have fetched the component and x is now ready.
- SingleModuleOptions.x?
type: <TODO: other type>|T
Initial value for x, which is the data structure the module is tracking.
Default: null
Controller Reference
The single controller is the main interface by which you interact with the single module– and thus your state management library. Check here for a primer on controllers as a concept.
- class SingleController()
interface
- Extends:
BaseController()
- SingleController.deleted
type: boolean
getter/setter to indicate whether the remote value we’re tracking has been deleted.
- SingleController.endpoint
type: string
The endpoint property on the single module. This is a getter/setter, so you can update the endpoint.
- SingleController.errors
type: default
Retrieves the stored error information from our last attempt at
getting
the remote object.
- SingleController.failed
type: boolean
getter/setter to indicate that the attempt to fetch
x
failed. Can be set manually if needed for testing.
- SingleController.fetching
type: boolean
getter/setter to indicate that
x
is being fetched via get request. Can be set manually if needed for testing.
- SingleController.moduleType
type: <TODO: other type>
Returns ‘single’, the type of module this controller handles.
- SingleController.p
type: BoundPatchers<T>
A proxy object that creates patchers for any property on the object. So, for instance, if you have a type:
declare interface MyType { id: number, name: string, fun: boolean, } Then this object will contain the keys `id`, `name`, and `fun`. Each of these attributes will be a :js:class:`Patcher` bound to its specific field.
- SingleController.params
type: <TODO: other type>|QueryParams
getter/setter for query parameters used when interacting with the endpoint.
- SingleController.ready
type: boolean
getter/setter to indicate that
x
is initialized and ready to be interacted with. Mostly set internally, but can be explicitly set during testing.
- SingleController.x
type: <TODO: other type>|T
The data structure you’re tracking in the single module. It can also be null if you’ve neither fetched nor preset its value. This is a getter and setter, so you can entirely replace
x
if you like.Note that you should not mutate the attributes of x directly. Instead, if you need to change
x
, useupdateX
, :js:attr`setX <SingleController.setX>`, set thex
setter directly, or use the Patchers.
- SingleController.delete()
Sends a deletion request to the server. If successful, marks
x
as null and sets thedeleted
flag to true and sets thedeleted
flag to true.- Returns
Promise<void> –
- SingleController.get()
Performs a get request. Will update the value of
x
based on what it retrieves, and return a promise containing the new value.- Returns
Promise<T> –
- SingleController.getOnce()
Fetch this object from its endpoint. No matter how many times this function is called, it only runs once, allowing you to call it in any component that may need the function and not worry about several requests being sent.
- SingleController.initializePatcherSettings(attrName)
Initialize a patcher’s settings. You might need this if the object returned from your initial fetching is incomplete and does not have the field you want to add a patcher for, or if you need to initialize a patcher without fetching the remote resource for some reason.
- Arguments
attrName (
AttrName()
) –
- SingleController.makeReady(val)
Set x and mark :js:attr`ready <SingleController.ready>` as true. Mostly useful for testing.
- Arguments
val (
T()
) –
- SingleController.patch(val)
Sends a patch request. Updates
x
with the value returned from the server, and returns a promise containing the new value.- Arguments
val (
Partial
) –
- Returns
Promise<T> –
- SingleController.post(val)
Sends a post request. DOES NOT update
x
with the value returned from the server. Returns a promise containing the value the server sent back.- Arguments
val (
I()
) –
- Returns
Promise<AxiosResponse<O, any>> –
Patchers
Patchers are a special, controller-like wrapper around the attributes of singles. They act as proxies for sending patch requests to a server. This is especially useful for cases like Vue’s v-model, but also allows for more terse functions in the case of React’s event listeners.
Say you had a controller for a Product type:
declare interface Product {
id: number,
name: string,
description: string,
hidden: boolean,
}
You could update the value of hidden by setting its value on the autogenerated patcher:
// Output: false
console.log(controller.x.hidden)
controller.p.hidden.model = true
// Output: true
console.log(controller.p.hidden.model)
// Still false, as this value is canonical until the server update is completed:
console.log(controller.x.hidden)
// Also true, since the update is not complete:
console.log(controller.p.hidden.dirty)
The value on a Patcher’s model
field is instantly updated, and in the background, a patch request is dispatched to the endpoint
with the data {“hidden”: true}.
Up until the patcher succeeds, its dirty
flag stays true. If an error occurs while performing the patch request, errors will appear in controller.p.hidden.errors. See below for more attributes and methods.
- class Patcher()
A wrapper class around individual attributes on a single.
interface
- Patcher.attrName
type: AttrName
The name of the field we’re tracking on the single.
- Patcher.cached
type: <TODO: other type>|<TODO: other type>
The most recently set value on the field through the patcher. Compared against the real value on the single x’s field to determine if the value is :js:attr`dirty`.
- Patcher.controller
type: SingleController<T>
A reference to the SingleController, used for internal functions.
- Patcher.debouncedRawSet
type: DebouncedFunc<<TODO: reflection>>
The debounced function that
set
calls. You usually don’t want to call this directly. If you do, you’ll probably want to setcache
first.
- Patcher.dirty
type: boolean
A getter that returns true if the cached value does not match the value on the single’s x.
- Patcher.errors
type: string[]
An array of derived errors from the server when trying to patch this field.
- Patcher.loaded
type: boolean
Whether the underlying value has been loaded successfully (that is, is x set on the
SingleController()
?)
- Patcher.model
type: <TODO: other type>
A getter and setter that invokes the patch requesting machinery. That is, set this value to send a patch request.
This value will return the
cached
value. Setting this value is equivalent to runningset
.
- Patcher.moduleType
type: <TODO: other type>
Returns ‘patcher’, the type of ‘module’ this wrapper handles. Technically patchers aren’t modules, since their state is shared with singles, however this makes it consistent with similarly behaving controllers, which should have a moduleType property for easy identification.
- Patcher.patching
type: boolean
Whether a patch request is currently being sent. You might use this to determine whether a spinner should be shown.
- Patcher.rawValue
type: <TODO: other type>
Gets the current value of the :js:attr`attrName` field on x.
- Patcher.rawSet(val)
The raw set function that
debouncedSet
debounces. You usually don’t want to call this directly. If you do, you’ll probably want to setcache
first. This function performs the actual patch request and handles the resulting server response.- Arguments
val (
<TODO: other type>()
) –
- Patcher.set(val)
Sets a new value for the field, updating the
cache
and then runningdebouncedSet
.- Arguments
val (
<TODO: other type>()
) –