Skip to main content

Page & App Scope

To build Multi-Page Apps in Superblocks, it is important to understand how resources such as Frontend Variables, APIs, Timers, Events, and more are scoped. Scope enables you to keep your application cleanly organized, while also sharing and reusing resources and data across pages.

When you create a resource, you will choose whether this resource is created at the Page or App level. Resources can be created at either level via the Navigation menu or inline from any action menu.

Nav with app and page scopes

Create app or page variable inline

Page vs App-level resources

info

APIs do not yet support app scope; an API is scoped to a page and can only be invoked from that page. To reuse the response of an API across pages, store the response in a frontend variable scoped to the application.

At a high-level, each resource in a Superblocks Application must belong to either a specific page or the app. Whether a resource is Page or App level dictates where the resource can be accessed, as well as how other resources are references.

Page level

Most resources in your app, such as components, frontend variables, APIs, timers, and custom events are created at the page level. These resources belong to one page and are only accessible from that page.

App level

Frontend variables, timers, and custom events can be created at the app-level, which means they are shared across the app and are accessible from any page in the application.

Frontend variables

App-level frontend variables are preserved as you switch between pages. These variables are useful for sharing authentication state, user data, cached API responses, or other global data across your application.

App-level frontend variables come with the same persistence options: Temporary and Local Storage.

  • Temporary variables are preserved only for the current session. This means they are preserved as the user navigates between pages, but are lost when the user refreshes the page or closes the browser.
  • Local Storage variables are preserved across sessions. This means they are saved to the user's browser and are available even if the user closes the browser and returns later.

Timers

App-level timers are shared across all pages in your application. This is useful for creating global timers, such as a session timeout timer, that need to be active regardless of which page the user is on.

These timers can be started, stopped, and reset from any page in your application.

Custom events

App-level custom events are shared across all pages in your application. This is useful for sharing common frontend logic that can be triggered from any page. For example, you might have a custom event that triggers a global error message to be displayed and sets an app-level variable to track the error state.

Referencing page and app level resources

Scope determines both:

  1. Where a resource can be accessed
  2. How the resource is referenced

From page scope

From a specific page, you can access other resources that are part of the same page as well as resources at the app-level. For example, when writing some JavaScript code inside of a component property or page-level state variable, you can reference entities at the page or app-level.

What can be referenced from this scope?How do I reference resources at this level?
Other page-level resources on this specific pageNo prefix - Ex: {{ variable1.value }} refers to a page-level variable variable1
App-level resourcesApp. prefix - Ex: {{ App.variable1.value }} refers to an app-level variable variable1

From app scope

From the app-level, you can only reference other app-level resources. To reference an app-level resource from another app-level resource, you do not need to use a prefix. For example, {{ variable1.value }} refers to an app-level variable variable1.

What can be referenced from this scope?How do I reference resources at this level?
App-level resourcesNo prefix - Ex: {{ variable1.value }} refers to an app-level variable variable1

Example - caching an API response using App State

Consider the case where I have a Customers and CustomerDetail page.

When a user navigates to the Customers page, I want to fetch a list of customers and cache this list so that when the user navigates to the CustomerDetail page, I don't need to re-fetch the details for a specific customer if they were already fetched on the Customers page.

This type of caching will avoid unnecessary API calls and improve the performance of my application.

On my Customers page, I can create an app-level frontend variable cachedCustomersObject where I can store the list of customers I fetch from my API.

Cached customers state variable

Now, I navigate to my getCustomers API. This API queries my list of customers from the database.

I want to turn this list into an object keyed by Customer ID, so that I can easily look up the user's information by ID on the Customer Detail page. I add a RunJS response event handler to my API with the following code.

function arrayToObjectById(array) {
return array.reduce((obj, item) => {
obj[item.id] = item;
return obj;
}, {});
}

// Convert the array of customers to an object keyed by ID
const result = arrayToObjectById(getCustomers.response);

// Merge the new object with the existing fetchedCustomers object
const mergedObject = {
...App.cachedCustomersObject.value,
...result,
};

// Set the App state variable cachedCustomersObject to the value of the merged object
App.cachedCustomersObject.set(mergedObject);

Next, I'll go over to my CustomerDetail page. Here, I have an API getCurrentUser that queries user info for the relevant customer, per the ID passed in the URL route.

I need to keep this API, since the user can navigate directly to the CustomerDetail page without visiting the Customers page first.

However, I can now update my API to check if the user's information is already in the App.cachedCustomersObject object. If it is, I can simply return that cached information, rather than re-querying the database.

Check for cached user information

info

To implement more robust caching, you would likely want to consider a cache invalidation strategy, as well as a mechanism to update the cached data set when new data is fetched anywhere in the app.