SDK Helper
Apps NubeSDK rodam dentro de um web worker isolado, sem acesso direto ao DOM. Tudo que o app faz: ler o estado, renderizar componentes, navegar e armazenar dados passa pela instância do SDK que o runtime entrega ao ponto de entrada App(nube).
Na prática, essa instância nube acaba sendo passada por todas as funções e componentes do app, e alguns padrões se repetem em todo projeto: ler a página atual, estreitar tipos de página, renderizar um componente por produto, exibir um toast ao receber um evento.
@tiendanube/nube-sdk-helper concentra esses padrões em um conjunto de utilitários pequeno e fortemente tipado.
Instalação
npm
Yarn
pnpm
npm install @tiendanube/nube-sdk-helper @tiendanube/nube-sdk-types
yarn add @tiendanube/nube-sdk-helper @tiendanube/nube-sdk-types
pnpm add @tiendanube/nube-sdk-helper @tiendanube/nube-sdk-types
@tiendanube/nube-sdk-types é uma peer dependency e deve ser instalada junto.
Registrando a instância
O runtime entrega a instância do SDK apenas como argumento do ponto de entrada. A ideia central do helper é simples: registre uma vez, e todos os outros helpers chegam até ela por conta própria, sem precisar passar nube por toda a árvore do app.
import {
setNubeInstance,
getCurrentState,
ui,
} from "@tiendanube/nube-sdk-helper";
import type { NubeSDK } from "@tiendanube/nube-sdk-types";
export function App(nube: NubeSDK) {
setNubeInstance(nube); // call this first, before anything else
const state = getCurrentState();
ui.showToast(`You are on the ${state.location.page.type} page`);
}
Três funções gerenciam a instância:
setNubeInstance(nube): registra a instância (chame uma vez no topo doApp).getNubeInstance(): retorna a instância registrada, lançando um erro descritivo se ela ainda não foi registrada.clearNubeInstance(): limpa a instância (útil em testes).
Por que isso importa
Com a instância registrada globalmente, as ações mais comuns viram funções independentes que podem ser chamadas de qualquer lugar: um componente aninhado, um módulo utilitário, um event handler, sem precisar receber nube como parâmetro.
import { navigate, ui } from "@tiendanube/nube-sdk-helper";
// Em qualquer lugar do app, sem `nube` no escopo:
function onCheckoutClick() {
navigate("/checkout"); // routes to the path internally via the SDK instance
ui.showToast("Taking you to checkout...", "info");
}
Sem o helper, seria necessário ter uma referência a nube no escopo e chamar nube.getBrowserAPIs().navigate(...), além de construir o componente de toast manualmente. O helper reduz ambos a uma linha.
O mesmo se aplica ao armazenamento no browser:
import { browser } from "@tiendanube/nube-sdk-helper";
await browser.asyncLocalStorage.setItem("seen-banner", "true");
const seen = await browser.asyncLocalStorage.getItem("seen-banner");
Lendo o estado com seletores
Os seletores seguem um padrão consistente: chamados sem argumento, leem o estado atual do SDK; passando um estado explícito, tornam-se funções puras.
import { getCartItems, getPageType, getCustomer } from "@tiendanube/nube-sdk-helper";
// Sem argumento: lê o estado atual da instância do SDK.
const items = getCartItems();
const pageType = getPageType();
const customer = getCustomer();
// Com estado explícito: puro, ideal para testes unitários.
const itemsFromMock = getCartItems(mockState);
Passe um estado mock para qualquer seletor e ele se comporta como uma função pura: sem efeitos colaterais, sem depender da instância registrada. Esse padrão vale para toda a família de seletores.
Guards
Guards fazem dupla função: validam em runtime e estreitam o tipo para o TypeScript, desbloqueando os dados específicos da página tipados pelo compilador.
import { getCurrentState, isProductPage } from "@tiendanube/nube-sdk-helper";
const { page } = getCurrentState().location;
if (isProductPage(page)) {
// `page` is now narrowed to a ProductPage, so `page.data.product` is typed.
console.log(page.data.product.name);
}
Diferente de um cast (as ProductPage), os guards verificam a estrutura em runtime antes de estreitar o tipo. Se a condição não passar, o TypeScript não expõe page.data.product.
Há um guard para quase toda estrutura encontrada em um app NubeSDK:
- Páginas:
isProductPage,isCategoryPage,isCheckoutPage,isHomePage,isAllProductsPage,isSearchPage - Carrinho:
isCart,isCartItem,isCartValidationSuccess,isCartValidationPending,isCartValidationFail - Domínio:
isStore,isCustomer,isPayment,isShipping,isAddress, e mais - Componentes / dados de página:
isNubeComponent,hasProductList,hasSections,hasSingleProduct,isSectionWithProducts
Getters
Além dos seletores de estado, os getters expõem os metadados injetados pelo runtime sobre o app. Um exemplo útil é getScriptURL, que analisa a URL de onde o script do app foi carregado (cacheada como uma URL congelada):
import { getScriptURL, getScriptParam } from "@tiendanube/nube-sdk-helper";
const url = getScriptURL();
console.log("Script origin:", url.origin);
console.log("Script pathname:", url.pathname);
// Read configuration passed as query params on the script URL, e.g. ?variant=b
const variant = getScriptParam("variant"); // string | null
Essa é a forma idiomática de configurar um app a partir da tag de script, sem precisar de uma requisição adicional.
Page matching
pageMatch e onPage resolvem o mesmo problema de ângulos diferentes. pageMatch despacha uma vez contra um estado fornecido, e cada handler recebe o payload corretamente tipado para a sua página. onPage envolve pageMatch, mas subscreve à navegação, re-executando a cada mudança de página e retornando uma função de cancelamento.
Use pageMatch para uma decisão pontual com base no estado atual:
import { pageMatch, getCurrentState } from "@tiendanube/nube-sdk-helper";
// Runs once against the state you pass in.
pageMatch(getCurrentState(), {
product: (state, product) => console.log("Product:", product.name),
checkout: (state, checkout) => console.log("Step:", checkout.step),
});
Use onPage para reagir continuamente à navegação do usuário:
import { onPage } from "@tiendanube/nube-sdk-helper";
const stop = onPage({
product: (state, product) => trackProductView(product.id),
checkout: (state, checkout) => {
if (checkout.step === "success") trackPurchase();
},
// category / home handlers are optional
});
// Later, when you no longer need it:
stop();
Para checkout especificamente, onCheckoutStep permite reagir a um step específico:
import { onCheckoutStep } from "@tiendanube/nube-sdk-helper";
onCheckoutStep({
success: () => trackPurchase(),
});
Render
Uma necessidade frequente é renderizar algo em um slot de grade de produto: um badge, um label, um ícone. forEachProduct extrai todos os produtos do estado atual (independentemente do tipo de página), mapeia cada um por uma factory de renderização, descarta resultados vazios e atribui automaticamente um key único a partir do id do produto.
import { getNubeInstance, forEachProduct } from "@tiendanube/nube-sdk-helper";
getNubeInstance().render(
"product_grid_item_image_bottom_right",
forEachProduct((product) => <MyBadge product={product} />),
);
Sem JSX, a factory retorna um objeto de componente diretamente:
getNubeInstance().render(
"product_grid_item_image_bottom_right",
forEachProduct((product) => ({ type: "txt", children: product.name })),
);
Retornar null ou undefined da factory pula o produto: essas entradas são filtradas automaticamente.
Helpers de UI e eventos
ui agrupa as operações de view mais comuns, incluindo renderizar o mesmo componente em múltiplos slots em uma chamada:
import { ui } from "@tiendanube/nube-sdk-helper";
ui.renderAll(["corner_top_left", "corner_top_right"], {
type: "txt",
children: "Hi",
});
ui.showToast("Done!", "success");
ui.clear("corner_top_right");
onEvent e toastOn reduzem o padrão repetitivo de "escutar e reagir" a uma linha cada, ambos retornando uma função de cancelamento:
import { onEvent, toastOn } from "@tiendanube/nube-sdk-helper";
const off = onEvent("cart:update", (state) => {
console.log("items:", state.cart.items.length);
});
// Later, when you no longer need it:
off();
toastOn("cart:add:success", "Added to cart", "success");
toastOn("cart:update", (state) => `Cart: ${state.cart.items.length} items`);
Próximos passos
Help us improve NubeSDK
Found an issue or have a suggestion? Let us know on GitHub.