Recentemente, precisei desenvolver uma integração de checkout VTEX dentro de um aplicativo React Native. O desafio era garantir que a experiência de compra fosse fluida, mantendo o estado do carrinho perfeitamente sincronizado entre o ambiente nativo do app e a finalização da compra na WebView.
Para resolver isso, utilizei o Zustand para o gerenciamento de estado global e a API de Checkout da VTEX para manipular o orderFormId.
A Arquitetura da Solução
A ideia central foi: o App gerencia os produtos e quantidades através de uma store leve Zustand e, antes de abrir o checkout, sincronizamos tudo com a VTEX via API.
1. Gerenciando o Carrinho com Zustand
A store armazena o orderFormId e persiste os dados para que o carrinho não se perca. Aqui, podemos escolher entre o AsyncStorage (padrão) ou o MMKV (para performance ultra-rápida).
import { create } from 'zustand';
import { persist, createJSONStorage } from 'zustand/middleware';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { MMKV } from 'react-native-mmkv';
// Opção com MMKV (Alta Performance)
const storage = new MMKV();
const mmkvStorage = {
setItem: (name, value) => storage.set(name, value),
getItem: (name) => storage.getString(name) ?? null,
removeItem: (name) => storage.delete(name),
};
export const useCartStore = create(
persist(
(set) => ({
orderFormId: null,
items: [],
setOrderFormId: (id) => set({ orderFormId: id }),
addToCart: (item) => set((state) => ({ items: [...state.items, item] })),
clearCart: () => set({ items: [], orderFormId: null }),
}),
{
name: 'cart-storage',
// Troque 'mmkvStorage' por 'AsyncStorage' se preferir o padrão
storage: createJSONStorage(() => mmkvStorage),
}
)
);
Para esse projeto, utilizei o MMKV pela velocidade de leitura/escrita, mas a estrutura funciona perfeitamente com AsyncStorage também.
2. Sincronizando com a API da VTEX
Antes de navegar para a tela de checkout, enviamos os itens para o orderForm específico. Isso evita disparar várias chamadas de rede desnecessárias durante a navegação.
const syncCartWithVtex = async (orderFormId, items) => {
try {
await fetch(`https://{ACCOUNT}.vtexcommercestable.com.br/api/checkout/pub/orderForm/${orderFormId}/items`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
orderItems: items.map(i => ({ id: i.id, quantity: i.quantity, seller: "1" }))
}),
});
} catch (error) {
console.error("Erro na sincronização:", error);
}
};
DICA: A VTEX às vezes exige que o cabeçalho vtex-id-client-authtoken seja enviado se o usuário já estiver autenticado no app, para que o carrinho não fique como "anônimo"
3. O Checkout na WebView
A sacada foi é injetar o orderFormId na URL da WebView. Assim, o checkout da VTEX já abre com todos os itens que o usuário escolheu no app.
import { WebView } from 'react-native-webview';
const VtexCheckout = () => {
const { orderFormId } = useCartStore();
// URL que vincula a sessão ao carrinho do App
const checkoutUrl = `https://www.sualoja.com.br/checkout/?orderFormId=${orderFormId}#/cart`;
return (
<WebView
source={{ uri: checkoutUrl }}
sharedCookiesEnabled={true} //PARA MANTER A SESSÃO
startInLoadingState={true}
/>
);
};
Lições aprendidas
Performance: Sincronizar o estado via API antes de abrir a WebView entrega uma experiência muito mais "nativa" do que tentar manipular o DOM da página carregada.
Persistência: O uso do Zustand com middleware de persistência é imbatível para lidar com carrinhos em dispositivos móveis.
Desenvolver soluções de e-commerce de alta performance é o que move a gente na Converte .
E você, já teve que lidar com essa ponte entre o nativo e o web no e-commerce? Vamos trocar uma ideia nos comentários!
Top comments (0)