Skip to content
Twilight React Playground
ثيم رائدaren

updateTwilightContext

functionAdvancedserverbrowserlive demo

Writes values into the current twilight context: the request's own on the server, the page's single context in the browser.

import { updateTwilightContext } from '@salla.sa/twilight-theme-engine/tanstack';

In plain words

The engine keeps page-wide facts (settings, language, location, auth token) in the twilight context. The router and the root route write them as pages load, with updateTwilightContext().

A theme rarely needs it. The safe place for values of your own is extras, a field the engine stores for you and never reads itself.

Signature

function updateTwilightContext(partial: Partial<TwilightContext>): void

Try it live

Each button calls updateTwilightContext({ extras }), then reads the context back. The demo restores the old value when you leave.Try this: write the campaign, then the banner: campaign is gone. extras is replaced, not merged.
Storefront canvas · en · LTR
Runs in the browser…
Controls
What a theme writes
import {
  getTwilightContext,
  updateTwilightContext,
} from '@salla.sa/twilight-theme-engine/tanstack';

// In an event handler or effect, never while rendering.
export function rememberCampaign() {
  const { extras } = getTwilightContext();
  // extras is replaced as a whole, so spread what is already there.
  updateTwilightContext({ extras: { ...extras, campaign: 'summer-sale' } });
}

Example

app/components/CampaignCapture.tsx
import { useEffect } from 'react';
import { useLocation } from '@salla.sa/twilight-theme-engine/providers';
import {
  getTwilightContext,
  updateTwilightContext,
} from '@salla.sa/twilight-theme-engine/tanstack';

// Remembers ?utm_campaign= for loaders that run in this browser later.
export function CampaignCapture() {
  const { search } = useLocation<{ utm_campaign?: string }>();
  const campaign = search.utm_campaign ? String(search.utm_campaign) : null;

  useEffect(() => {
    if (!campaign) return;
    const { extras } = getTwilightContext();
    updateTwilightContext({ extras: { ...extras, campaign } });
  }, [campaign]);

  return null;
}

How it behaves

  • queryClient, settings, locale, routeId and i18n ignore null and undefined, so they cannot be cleared. location is merged into the current location field by field.

  • authToken, scope, storeId, storeBase, versionId and requestHost accept null to clear. page, appsSnippets, appsSettings and extras are replaced by whatever you pass, undefined included. scopeId sets scope to { id } when scope itself is not given.

  • In the browser it notifies subscribers, so useRouteId() and the page-detection hooks render again. On the server nothing is notified.

  • On the server it writes into the current request's context, and throws [Twilight] No request context… outside one. Call it in handlers, effects, loaders or middleware, never while a component renders.

Gotchas

  • The engine overwrites what it owns: every navigation writes location, routeId and settings again, and the root route writes locale, settings, i18n and authToken. A value you put in those fields lasts until the next navigation. Keep your own values in extras.

  • extras is replaced, not merged: updateTwilightContext({ extras: { banner } }) removes a campaign stored before. Spread the current extras first, as the example does.

  • A value written on the server stays there. Hydration copies settings, locale, i18n, auth token, location, page, route id and the app snippets and settings into the browser, nothing else (src/tanstack/router.tsx), so extras written by a middleware is undefined in the browser. Return what the browser needs from a loader.

Related

Source and docs