Signals and subscriptions
This chapter covers the core tools for working with data in StartupJS: the root signal $, subscriptions with useSub, and local signals with $().
The root signal: $
$ is the entry point to all your data. Think of it as the root of a tree. You navigate the tree using dot notation, just like a JavaScript object:
Each of these expressions creates a signal -- a reactive pointer to that piece of data. A signal does not hold data itself. It knows where the data is and provides methods to read and write it.
Subscribing to a document: useSub
Before you can read data from the database, you must subscribe to it. Use the useSub hook inside a component wrapped with observer:
useSub($.todos[todoId]) subscribes to a single document. The returned $todo is a signal. Use .get() to read a field's value and .set() to update it.
When the component unmounts, the subscription is automatically cleaned up.
Subscribing to a query: useSub with a query object
Pass a query object as the second argument to subscribe to multiple documents:
This subscribes to all documents in the todos collection where completed is false. The result, $todos, is a query signal -- an iterable collection of document signals.
You can loop over it:
Or use a for...of loop:
An empty query {} returns all documents in the collection:
Subscribing by IDs
To subscribe to specific documents by their IDs, use the $in operator:
This uses MongoDB's $in operator to match documents whose _id is in the given array.
Subscribing to one document by query
To get a single document matching a query, use $limit: 1:
$limit is a query modifier that caps the number of returned documents.
The result is still a query signal. Access the first (and only) item by iterating or using .find().
Query signal methods
Query signals support several useful methods:
.map(callback)-- transform each document signal.reduce(callback, initial)-- reduce to a single value.find(predicate)-- find the first matching document signal.getIds()-- returns the array of document IDs
Local signals: $()
For component-level state that does not need to be stored in the database, create a local signal with the $() function:
Local signals work like useState but integrate with the signal system. They are reactive -- components that read them re-render when they change.
You can also destructure object signals:
Private collections
Collections that start with _ are private -- they live only on the client and are never sent to the server. They are useful for storing temporary UI state that multiple components need to share.
The two most common private collections are:
$._page-- data scoped to the current page. It gets cleared when the user navigates away.$._session-- data scoped to the current browser session. It persists across page navigations but is lost when the tab is closed.
You can read and write them directly, without subscribing:
Since private collections are local-only, you do not need useSub for them. Just use $._page or $._session directly.
Using sub outside React
In non-React code (server-side scripts, background jobs, etc.), use the sub function instead of useSub. It returns a promise:
For queries: