# Run app code on a page (https://docs.salla.dev/twilight/react/recipes/run-app-code-on-a-page)



Use this when a store app or a snippet adds something to one kind of page, such as a widget on every product page.

**Goal:** the code runs on each product page the customer opens, in a React theme and a classic theme alike.

On a classic theme every page is a full load, so a snippet can check the page once:

```js
// Runs once. In the React theme that is only the page the customer landed on.
if (Salla.url.is_page('product.single')) mountWidget();
```

In the React theme, links navigate in the browser without reloading. That snippet runs once, on the first page, and the engine renders later pages fresh. A widget it added is replaced, and a product page the customer opens later never gets one.

## Listen for `page::view` [#listen-for-pageview]

The Twilight SDK dispatches `page::view` with the page the customer is looking at: once when it has started, then after every navigation in the browser (it follows the engine's `route::changed`). A classic theme loads each page, so there it fires once per page too. The same code works in both:

```js
Salla.event.on('page::view', (page) => {
  if (page.slug === 'product.single') mountWidget(page.id);
  else removeWidget();
});
```

The handler gets the page: `slug`, `id`, `title`, `url`, and `breadcrumbs` when the page has them. A 404 sends an empty object, so check `slug`.

* **It is sticky.** A handler added after the first `page::view`, such as a snippet that loads late, is called straight away with the page on screen, then on every later one.
* **Leaving is yours to handle.** There is no separate event for it: the next `page::view` is the signal, as `removeWidget()` above shows.
* **Opening another product is a new page view.** Changing filters or sorting on the same page is not.

<Callout type="info">
  Snippets that still check `Salla.url.is_page('product.single')` once, outside a `page::view` handler, keep working: the engine loads the page fully when the customer navigates to or from a page they name, as classic themes do. Those navigations lose the speed of in-browser navigation, so move the snippet to `page::view`.

  Only a positive check that names the page counts. A negated check (`!Salla.url.is_page('cart')`), a read of `page.slug` or `config.get('page')`, or a slug held in a variable runs once, on the page the customer landed on, because reloading for it would reload every page.
</Callout>

## Where to go next [#where-to-go-next]

* [Salla SDK and events](https://docs.salla.dev/twilight/react/guide/salla-sdk-and-events), for `route::changed`, the event `page::view` follows.
* [Add content to a slot](https://docs.salla.dev/twilight/react/recipes/add-content-to-a-slot), for a place in the page that survives navigation.
