1. Interactions with Sitecore

Save and restore app URL state

Required extension points: any

Required SDK packages: client

Required API access: none

Use application.urlState to save a view in the host URL and restore it after a reload or when opening a shared link.

Before you begin

Restore a saved view

To restore a view in the component where you run useMarketplaceClient:

  1. Update your imports and define the view type and a validator outside the component. Use a type alias, not an interface, to ensure the view is compatible with JsonObject:

    import { useEffect, useRef, useState } from "react";
    import type { JsonObject } from "@sitecore-marketplace-sdk/client";
    
    type ViewState = { tab: "overview" | "seo"; range: "7d" | "30d" };
    const DEFAULT_VIEW: ViewState = { tab: "overview", range: "7d" };
    
    function parseViewState(raw: JsonObject | null | undefined): ViewState | null {
      if (!raw) return null;
      const { tab, range } = raw;
      if (tab !== "overview" && tab !== "seo") return null;
      if (range !== "7d" && range !== "30d") return null;
      return { tab, range };
    }
  2. Inside the component, add state and an Effect Hook that queries the host after the SDK connects:

    const [view, setView] = useState<ViewState>(DEFAULT_VIEW);
    const [isSaving, setIsSaving] = useState(false);
    const hasChanged = useRef(false);
    
    useEffect(() => {
      if (!client) return;
      let active = true;
      client.query("application.urlState")
        .then(({ data, error }) => {
          if (!active || hasChanged.current) return;
          if (error) {
            console.error("Error restoring app URL state:", error);
            return;
          }
          const savedView = parseViewState(data?.state);
          if (data?.state && !savedView) {
            console.warn("Ignoring invalid saved view.");
          }
          setView(savedView ?? DEFAULT_VIEW);
        })
        .catch((error) => console.error("Error querying app URL state:", error));
      return () => { active = false; };
    }, [client]);

    The validator checks the saved values before using them. The ref prevents a late response from overwriting a view the user has already changed.

Save or clear a view

  1. In the same component, add a function to save a complete view object or clear it with null:
    const saveView = async (state: ViewState | null) => {
      if (!client) {
        console.error("The Marketplace client is not initialized.");
        return;
      }
      hasChanged.current = true;
      setView(state ?? DEFAULT_VIEW);
      setIsSaving(true);
      try {
        await client.mutate("application.urlState", { params: { state } });
      } catch (error) {
        console.error("Error saving app URL state:", error);
      } finally {
        setIsSaving(false);
      }
    };
  2. Add controls to your existing return statement, then save your changes:
    <>
      <p>Tab: {view.tab}. Date range: {view.range}.</p>
      <button disabled={!client || isSaving} onClick={() => saveView({ tab: "seo", range: "30d" })}>Show SEO</button>
      <button disabled={!client || isSaving} onClick={() => saveView(null)}>Reset view</button>
    </>
    This adds a Show SEO button and a Reset view button to your app's UI. If you add other controls, set hasChanged.current = true when the user changes the view.

Test saving and restoring a view

  1. Open your Marketplace app in one of its extension points and click Show SEO. Wait for the host URL to update, then reload the page. The view shows seo and 30d. This shows that the app URL state is successfully restored.
  2. Click Reset view, wait for the URL update, then reload. The view shows overview and 7d. This shows that the app URL state is successfully cleared.
If you have suggestions for improving this article, let us know!