[{"data":1,"prerenderedAt":4450},["ShallowReactive",2],{"blog-vuex-vs-pinia":3},{"id":4,"title":5,"author":6,"body":7,"date":4435,"description":4436,"extension":4437,"image":4438,"meta":4439,"navigation":167,"path":4440,"seo":4441,"stem":4442,"tags":4443,"__hash__":4449},"blog\u002Fblog\u002Fvuex-vs-pinia.md","Vuex vs Pinia: Guia Completo de Gerenciamento de Estado no Vue.js","Larissa Santos",{"type":8,"value":9,"toc":4401},"minimark",[10,19,22,25,30,33,45,52,55,66,68,72,75,80,88,94,100,106,116,119,808,811,1002,1006,1026,1375,1389,1393,1396,1399,1403,1414,1417,1435,1437,1441,1444,1451,1455,1458,1463,1468,1473,1480,1483,1995,2001,2254,2264,2268,2291,2659,2672,2676,2679,2989,3014,3018,3021,3178,3184,3188,3200,3252,3255,3257,3261,3264,3268,3338,3342,3345,3490,3493,3609,3613,3623,3736,3739,3910,3914,3925,3927,3931,3935,3938,3942,3945,3949,3952,3956,3959,3963,3969,3971,3975,3980,3983,3988,3991,3993,3997,4006,4020,4329,4332,4334,4338,4341,4344,4351,4355,4379,4383,4397],[11,12,13,14,18],"p",{},"Se você trabalha com Vue há algum tempo, já deve ter se perguntado: ",[15,16,17],"em",{},"quando usar Vuex e quando usar Pinia?"," Ou talvez você esteja iniciando um novo projeto e não sabe qual das duas escolher. Esse artigo foi escrito exatamente para responder essas perguntas de forma prática, com exemplos reais e sem enrolação.",[11,20,21],{},"Vamos do conceito fundamental até a comparação técnica profunda entre as duas bibliotecas, passando por exemplos de código lado a lado. Ao final, você vai saber exatamente o que cada uma oferece e quando faz sentido usar cada uma.",[23,24],"hr",{},[26,27,29],"h2",{"id":28},"o-que-é-gerenciamento-de-estado-e-por-que-ele-importa","O que é Gerenciamento de Estado e por que ele importa?",[11,31,32],{},"Antes de comparar as ferramentas, vale entender o problema que elas resolvem.",[11,34,35,36,40,41,44],{},"Em aplicações Vue pequenas, o estado de cada componente vive dentro dele mesmo. Um campo de formulário, um toggle de menu, um contador: tudo funciona muito bem com ",[37,38,39],"code",{},"data()"," ou ",[37,42,43],{},"ref()"," localmente. O problema começa quando componentes que não possuem relação direta na árvore de componentes precisam compartilhar os mesmos dados.",[11,46,47,48,51],{},"Imagine um e-commerce com um componente de cabeçalho que exibe o número de itens no carrinho, um componente de lista de produtos que adiciona itens a ele, e uma página de checkout que consome esses mesmos dados. Passar essas informações via props através de múltiplas camadas de componentes (o famoso ",[15,49,50],{},"prop drilling",") torna o código frágil e difícil de manter. Usar eventos para comunicar componentes que não são pai e filho é ainda mais trabalhoso.",[11,53,54],{},"A solução é centralizar o estado compartilhado em um lugar único, acessível por qualquer componente da aplicação. É exatamente isso que bibliotecas como Vuex e Pinia fazem.",[11,56,57,58,65],{},"Vale mencionar que a ideia por trás de uma store não é tão diferente de algo que o JavaScript já faz nativamente: ",[59,60,64],"a",{"href":61,"rel":62},"https:\u002F\u002Flarisantos.vercel.app\u002Fblog\u002Fclosures-javascript",[63],"nofollow","closures",". Uma função que mantém um estado interno protegido e expõe métodos para manipulá-lo é, na essência, o mesmo princípio que os frameworks formalizaram. Se esse conceito ainda não está claro para você, vale a leitura antes de seguir em frente.",[23,67],{},[26,69,71],{"id":70},"vuex-a-solução-consagrada","Vuex: a solução consagrada",[11,73,74],{},"O Vuex foi por anos a biblioteca oficial de gerenciamento de estado do Vue.js. Inspirado no padrão Flux (criado pelo Facebook) e no Redux (do ecossistema React), ele introduziu um modelo bastante estruturado e previsível para controlar o estado da aplicação.",[76,77,79],"h3",{"id":78},"a-arquitetura-do-vuex","A arquitetura do Vuex",[11,81,82,83,87],{},"O Vuex organiza o estado em um único objeto global chamado ",[84,85,86],"strong",{},"store",", e estabelece regras rígidas sobre como esse estado pode ser modificado. A estrutura é composta por quatro conceitos principais:",[11,89,90,93],{},[84,91,92],{},"State"," é onde os dados vivem. É o \"banco de dados\" da sua aplicação no lado do cliente.",[11,95,96,99],{},[84,97,98],{},"Getters"," são equivalentes a propriedades computadas para o store. Você os usa quando precisa derivar dados do estado, como filtrar uma lista ou calcular um total.",[11,101,102,105],{},[84,103,104],{},"Mutations"," são as únicas formas permitidas de modificar o estado de forma síncrona. Toda alteração no estado precisa passar por uma mutation, o que torna as mudanças rastreáveis e previsíveis.",[11,107,108,111,112,115],{},[84,109,110],{},"Actions"," lidam com operações assíncronas (como chamadas à API) e, ao final, fazem ",[37,113,114],{},"commit"," de uma mutation para de fato modificar o estado.",[11,117,118],{},"Veja como um store Vuex clássico se parece na prática:",[120,121,126],"pre",{"className":122,"code":123,"language":124,"meta":125,"style":125},"language-js shiki shiki-themes material-theme-lighter github-dark github-dark","import { createStore } from 'vuex'\n\nexport default createStore({\n  \u002F\u002F state: é onde todos os dados da aplicação vivem\n  \u002F\u002F pense nele como o \"banco de dados\" do lado do cliente\n  state: {\n    usuario: null,\n    carrinho: []\n  },\n\n  \u002F\u002F getters: são como computed properties, mas para o store\n  \u002F\u002F recebem o state como primeiro argumento e retornam um valor derivado\n  getters: {\n    totalItens(state) {\n      return state.carrinho.length\n    },\n    totalValor(state) {\n      \u002F\u002F reduce percorre o array somando o preço de cada item\n      return state.carrinho.reduce((acc, item) => acc + item.preco, 0)\n    }\n  },\n\n  \u002F\u002F mutations: a ÚNICA forma de modificar o state no Vuex\n  \u002F\u002F são sempre síncronas e recebem o state como primeiro argumento\n  \u002F\u002F por convenção, seus nomes são escritos em SNAKE_CASE maiúsculo\n  mutations: {\n    SET_USUARIO(state, usuario) {\n      state.usuario = usuario\n    },\n    ADICIONAR_AO_CARRINHO(state, produto) {\n      state.carrinho.push(produto)\n    },\n    REMOVER_DO_CARRINHO(state, produtoId) {\n      state.carrinho = state.carrinho.filter(item => item.id !== produtoId)\n    }\n  },\n\n  \u002F\u002F actions: lidam com lógica assíncrona (chamadas de API, etc.)\n  \u002F\u002F recebem um objeto de contexto { commit, state, getters, dispatch }\n  \u002F\u002F ao final, chamam commit() para acionar a mutation correspondente\n  actions: {\n    async buscarUsuario({ commit }, userId) {\n      const response = await fetch(`\u002Fapi\u002Fusuarios\u002F${userId}`)\n      const usuario = await response.json()\n      \u002F\u002F aqui está o ponto de atenção: a action não altera o state diretamente,\n      \u002F\u002F ela comita uma mutation que faz isso\n      commit('SET_USUARIO', usuario)\n    },\n    adicionarAoCarrinho({ commit }, produto) {\n      commit('ADICIONAR_AO_CARRINHO', produto)\n    }\n  }\n})\n","js","",[37,127,128,162,169,187,194,200,213,228,239,245,250,256,262,272,290,311,317,331,337,395,401,406,411,417,423,429,439,458,475,480,499,520,525,544,587,592,597,602,608,614,620,630,655,691,712,718,724,746,751,769,789,794,800],{"__ignoreMap":125},[129,130,133,137,141,145,148,151,155,159],"span",{"class":131,"line":132},"line",1,[129,134,136],{"class":135},"s3Er8","import",[129,138,140],{"class":139},"sG-J9"," {",[129,142,144],{"class":143},"sMo7A"," createStore",[129,146,147],{"class":139}," }",[129,149,150],{"class":135}," from",[129,152,154],{"class":153},"sF_wb"," '",[129,156,158],{"class":157},"s0vBq","vuex",[129,160,161],{"class":153},"'\n",[129,163,165],{"class":131,"line":164},2,[129,166,168],{"emptyLinePlaceholder":167},true,"\n",[129,170,172,175,178,181,184],{"class":131,"line":171},3,[129,173,174],{"class":135},"export",[129,176,177],{"class":135}," default",[129,179,144],{"class":180},"sK_r7",[129,182,183],{"class":143},"(",[129,185,186],{"class":139},"{\n",[129,188,190],{"class":131,"line":189},4,[129,191,193],{"class":192},"sutJx","  \u002F\u002F state: é onde todos os dados da aplicação vivem\n",[129,195,197],{"class":131,"line":196},5,[129,198,199],{"class":192},"  \u002F\u002F pense nele como o \"banco de dados\" do lado do cliente\n",[129,201,203,207,210],{"class":131,"line":202},6,[129,204,206],{"class":205},"sdv8B","  state",[129,208,209],{"class":139},":",[129,211,212],{"class":139}," {\n",[129,214,216,219,221,225],{"class":131,"line":215},7,[129,217,218],{"class":205},"    usuario",[129,220,209],{"class":139},[129,222,224],{"class":223},"swu5b"," null",[129,226,227],{"class":139},",\n",[129,229,231,234,236],{"class":131,"line":230},8,[129,232,233],{"class":205},"    carrinho",[129,235,209],{"class":139},[129,237,238],{"class":143}," []\n",[129,240,242],{"class":131,"line":241},9,[129,243,244],{"class":139},"  },\n",[129,246,248],{"class":131,"line":247},10,[129,249,168],{"emptyLinePlaceholder":167},[129,251,253],{"class":131,"line":252},11,[129,254,255],{"class":192},"  \u002F\u002F getters: são como computed properties, mas para o store\n",[129,257,259],{"class":131,"line":258},12,[129,260,261],{"class":192},"  \u002F\u002F recebem o state como primeiro argumento e retornam um valor derivado\n",[129,263,265,268,270],{"class":131,"line":264},13,[129,266,267],{"class":205},"  getters",[129,269,209],{"class":139},[129,271,212],{"class":139},[129,273,275,279,281,285,288],{"class":131,"line":274},14,[129,276,278],{"class":277},"s0u7J","    totalItens",[129,280,183],{"class":139},[129,282,284],{"class":283},"sk1zL","state",[129,286,287],{"class":139},")",[129,289,212],{"class":139},[129,291,293,296,299,302,305,307],{"class":131,"line":292},15,[129,294,295],{"class":135},"      return",[129,297,298],{"class":143}," state",[129,300,301],{"class":139},".",[129,303,304],{"class":143},"carrinho",[129,306,301],{"class":139},[129,308,310],{"class":309},"sVPC0","length\n",[129,312,314],{"class":131,"line":313},16,[129,315,316],{"class":139},"    },\n",[129,318,320,323,325,327,329],{"class":131,"line":319},17,[129,321,322],{"class":277},"    totalValor",[129,324,183],{"class":139},[129,326,284],{"class":283},[129,328,287],{"class":139},[129,330,212],{"class":139},[129,332,334],{"class":131,"line":333},18,[129,335,336],{"class":192},"      \u002F\u002F reduce percorre o array somando o preço de cada item\n",[129,338,340,342,344,346,348,350,353,355,357,360,363,366,368,372,375,379,381,383,386,388,392],{"class":131,"line":339},19,[129,341,295],{"class":135},[129,343,298],{"class":143},[129,345,301],{"class":139},[129,347,304],{"class":143},[129,349,301],{"class":139},[129,351,352],{"class":180},"reduce",[129,354,183],{"class":205},[129,356,183],{"class":139},[129,358,359],{"class":283},"acc",[129,361,362],{"class":139},",",[129,364,365],{"class":283}," item",[129,367,287],{"class":139},[129,369,371],{"class":370},"sFsEu"," =>",[129,373,374],{"class":143}," acc",[129,376,378],{"class":377},"sFfmW"," +",[129,380,365],{"class":143},[129,382,301],{"class":139},[129,384,385],{"class":143},"preco",[129,387,362],{"class":139},[129,389,391],{"class":390},"s_k96"," 0",[129,393,394],{"class":205},")\n",[129,396,398],{"class":131,"line":397},20,[129,399,400],{"class":139},"    }\n",[129,402,404],{"class":131,"line":403},21,[129,405,244],{"class":139},[129,407,409],{"class":131,"line":408},22,[129,410,168],{"emptyLinePlaceholder":167},[129,412,414],{"class":131,"line":413},23,[129,415,416],{"class":192},"  \u002F\u002F mutations: a ÚNICA forma de modificar o state no Vuex\n",[129,418,420],{"class":131,"line":419},24,[129,421,422],{"class":192},"  \u002F\u002F são sempre síncronas e recebem o state como primeiro argumento\n",[129,424,426],{"class":131,"line":425},25,[129,427,428],{"class":192},"  \u002F\u002F por convenção, seus nomes são escritos em SNAKE_CASE maiúsculo\n",[129,430,432,435,437],{"class":131,"line":431},26,[129,433,434],{"class":205},"  mutations",[129,436,209],{"class":139},[129,438,212],{"class":139},[129,440,442,445,447,449,451,454,456],{"class":131,"line":441},27,[129,443,444],{"class":277},"    SET_USUARIO",[129,446,183],{"class":139},[129,448,284],{"class":283},[129,450,362],{"class":139},[129,452,453],{"class":283}," usuario",[129,455,287],{"class":139},[129,457,212],{"class":139},[129,459,461,464,466,469,472],{"class":131,"line":460},28,[129,462,463],{"class":143},"      state",[129,465,301],{"class":139},[129,467,468],{"class":143},"usuario",[129,470,471],{"class":377}," =",[129,473,474],{"class":143}," usuario\n",[129,476,478],{"class":131,"line":477},29,[129,479,316],{"class":139},[129,481,483,486,488,490,492,495,497],{"class":131,"line":482},30,[129,484,485],{"class":277},"    ADICIONAR_AO_CARRINHO",[129,487,183],{"class":139},[129,489,284],{"class":283},[129,491,362],{"class":139},[129,493,494],{"class":283}," produto",[129,496,287],{"class":139},[129,498,212],{"class":139},[129,500,502,504,506,508,510,513,515,518],{"class":131,"line":501},31,[129,503,463],{"class":143},[129,505,301],{"class":139},[129,507,304],{"class":143},[129,509,301],{"class":139},[129,511,512],{"class":180},"push",[129,514,183],{"class":205},[129,516,517],{"class":143},"produto",[129,519,394],{"class":205},[129,521,523],{"class":131,"line":522},32,[129,524,316],{"class":139},[129,526,528,531,533,535,537,540,542],{"class":131,"line":527},33,[129,529,530],{"class":277},"    REMOVER_DO_CARRINHO",[129,532,183],{"class":139},[129,534,284],{"class":283},[129,536,362],{"class":139},[129,538,539],{"class":283}," produtoId",[129,541,287],{"class":139},[129,543,212],{"class":139},[129,545,547,549,551,553,555,557,559,561,563,566,568,571,573,575,577,580,583,585],{"class":131,"line":546},34,[129,548,463],{"class":143},[129,550,301],{"class":139},[129,552,304],{"class":143},[129,554,471],{"class":377},[129,556,298],{"class":143},[129,558,301],{"class":139},[129,560,304],{"class":143},[129,562,301],{"class":139},[129,564,565],{"class":180},"filter",[129,567,183],{"class":205},[129,569,570],{"class":283},"item",[129,572,371],{"class":370},[129,574,365],{"class":143},[129,576,301],{"class":139},[129,578,579],{"class":143},"id",[129,581,582],{"class":377}," !==",[129,584,539],{"class":143},[129,586,394],{"class":205},[129,588,590],{"class":131,"line":589},35,[129,591,400],{"class":139},[129,593,595],{"class":131,"line":594},36,[129,596,244],{"class":139},[129,598,600],{"class":131,"line":599},37,[129,601,168],{"emptyLinePlaceholder":167},[129,603,605],{"class":131,"line":604},38,[129,606,607],{"class":192},"  \u002F\u002F actions: lidam com lógica assíncrona (chamadas de API, etc.)\n",[129,609,611],{"class":131,"line":610},39,[129,612,613],{"class":192},"  \u002F\u002F recebem um objeto de contexto { commit, state, getters, dispatch }\n",[129,615,617],{"class":131,"line":616},40,[129,618,619],{"class":192},"  \u002F\u002F ao final, chamam commit() para acionar a mutation correspondente\n",[129,621,623,626,628],{"class":131,"line":622},41,[129,624,625],{"class":205},"  actions",[129,627,209],{"class":139},[129,629,212],{"class":139},[129,631,633,636,639,642,645,648,651,653],{"class":131,"line":632},42,[129,634,635],{"class":370},"    async",[129,637,638],{"class":277}," buscarUsuario",[129,640,641],{"class":139},"({",[129,643,644],{"class":283}," commit",[129,646,647],{"class":139}," },",[129,649,650],{"class":283}," userId",[129,652,287],{"class":139},[129,654,212],{"class":139},[129,656,658,661,664,666,669,672,674,677,680,683,686,689],{"class":131,"line":657},43,[129,659,660],{"class":370},"      const",[129,662,663],{"class":309}," response",[129,665,471],{"class":377},[129,667,668],{"class":135}," await",[129,670,671],{"class":180}," fetch",[129,673,183],{"class":205},[129,675,676],{"class":153},"`",[129,678,679],{"class":157},"\u002Fapi\u002Fusuarios\u002F",[129,681,682],{"class":153},"${",[129,684,685],{"class":143},"userId",[129,687,688],{"class":153},"}`",[129,690,394],{"class":205},[129,692,694,696,698,700,702,704,706,709],{"class":131,"line":693},44,[129,695,660],{"class":370},[129,697,453],{"class":309},[129,699,471],{"class":377},[129,701,668],{"class":135},[129,703,663],{"class":143},[129,705,301],{"class":139},[129,707,708],{"class":180},"json",[129,710,711],{"class":205},"()\n",[129,713,715],{"class":131,"line":714},45,[129,716,717],{"class":192},"      \u002F\u002F aqui está o ponto de atenção: a action não altera o state diretamente,\n",[129,719,721],{"class":131,"line":720},46,[129,722,723],{"class":192},"      \u002F\u002F ela comita uma mutation que faz isso\n",[129,725,727,730,732,735,738,740,742,744],{"class":131,"line":726},47,[129,728,729],{"class":180},"      commit",[129,731,183],{"class":205},[129,733,734],{"class":153},"'",[129,736,737],{"class":157},"SET_USUARIO",[129,739,734],{"class":153},[129,741,362],{"class":139},[129,743,453],{"class":143},[129,745,394],{"class":205},[129,747,749],{"class":131,"line":748},48,[129,750,316],{"class":139},[129,752,754,757,759,761,763,765,767],{"class":131,"line":753},49,[129,755,756],{"class":277},"    adicionarAoCarrinho",[129,758,641],{"class":139},[129,760,644],{"class":283},[129,762,647],{"class":139},[129,764,494],{"class":283},[129,766,287],{"class":139},[129,768,212],{"class":139},[129,770,772,774,776,778,781,783,785,787],{"class":131,"line":771},50,[129,773,729],{"class":180},[129,775,183],{"class":205},[129,777,734],{"class":153},[129,779,780],{"class":157},"ADICIONAR_AO_CARRINHO",[129,782,734],{"class":153},[129,784,362],{"class":139},[129,786,494],{"class":143},[129,788,394],{"class":205},[129,790,792],{"class":131,"line":791},51,[129,793,400],{"class":139},[129,795,797],{"class":131,"line":796},52,[129,798,799],{"class":139},"  }\n",[129,801,803,806],{"class":131,"line":802},53,[129,804,805],{"class":139},"}",[129,807,394],{"class":143},[11,809,810],{},"E para consumir esse store dentro de um componente Vue 2 com Options API:",[120,812,814],{"className":122,"code":813,"language":124,"meta":125,"style":125},"import { mapState, mapGetters, mapActions } from 'vuex'\n\nexport default {\n  computed: {\n    \u002F\u002F mapState mapeia state.usuario e state.carrinho como computed properties\n    \u002F\u002F agora você acessa via this.usuario e this.carrinho no template\n    ...mapState(['usuario', 'carrinho']),\n\n    \u002F\u002F mapGetters faz o mesmo para os getters definidos no store\n    ...mapGetters(['totalItens', 'totalValor'])\n  },\n  methods: {\n    \u002F\u002F mapActions transforma as actions em métodos do componente\n    \u002F\u002F this.buscarUsuario(id) vai chamar store.dispatch('buscarUsuario', id)\n    ...mapActions(['buscarUsuario', 'adicionarAoCarrinho'])\n  }\n}\n",[37,815,816,845,849,857,866,871,876,906,910,915,943,947,956,961,966,993,997],{"__ignoreMap":125},[129,817,818,820,822,825,827,830,832,835,837,839,841,843],{"class":131,"line":132},[129,819,136],{"class":135},[129,821,140],{"class":139},[129,823,824],{"class":143}," mapState",[129,826,362],{"class":139},[129,828,829],{"class":143}," mapGetters",[129,831,362],{"class":139},[129,833,834],{"class":143}," mapActions",[129,836,147],{"class":139},[129,838,150],{"class":135},[129,840,154],{"class":153},[129,842,158],{"class":157},[129,844,161],{"class":153},[129,846,847],{"class":131,"line":164},[129,848,168],{"emptyLinePlaceholder":167},[129,850,851,853,855],{"class":131,"line":171},[129,852,174],{"class":135},[129,854,177],{"class":135},[129,856,212],{"class":139},[129,858,859,862,864],{"class":131,"line":189},[129,860,861],{"class":205},"  computed",[129,863,209],{"class":139},[129,865,212],{"class":139},[129,867,868],{"class":131,"line":196},[129,869,870],{"class":192},"    \u002F\u002F mapState mapeia state.usuario e state.carrinho como computed properties\n",[129,872,873],{"class":131,"line":202},[129,874,875],{"class":192},"    \u002F\u002F agora você acessa via this.usuario e this.carrinho no template\n",[129,877,878,881,884,887,889,891,893,895,897,899,901,904],{"class":131,"line":215},[129,879,880],{"class":377},"    ...",[129,882,883],{"class":180},"mapState",[129,885,886],{"class":143},"([",[129,888,734],{"class":153},[129,890,468],{"class":157},[129,892,734],{"class":153},[129,894,362],{"class":139},[129,896,154],{"class":153},[129,898,304],{"class":157},[129,900,734],{"class":153},[129,902,903],{"class":143},"])",[129,905,227],{"class":139},[129,907,908],{"class":131,"line":230},[129,909,168],{"emptyLinePlaceholder":167},[129,911,912],{"class":131,"line":241},[129,913,914],{"class":192},"    \u002F\u002F mapGetters faz o mesmo para os getters definidos no store\n",[129,916,917,919,922,924,926,929,931,933,935,938,940],{"class":131,"line":247},[129,918,880],{"class":377},[129,920,921],{"class":180},"mapGetters",[129,923,886],{"class":143},[129,925,734],{"class":153},[129,927,928],{"class":157},"totalItens",[129,930,734],{"class":153},[129,932,362],{"class":139},[129,934,154],{"class":153},[129,936,937],{"class":157},"totalValor",[129,939,734],{"class":153},[129,941,942],{"class":143},"])\n",[129,944,945],{"class":131,"line":252},[129,946,244],{"class":139},[129,948,949,952,954],{"class":131,"line":258},[129,950,951],{"class":205},"  methods",[129,953,209],{"class":139},[129,955,212],{"class":139},[129,957,958],{"class":131,"line":264},[129,959,960],{"class":192},"    \u002F\u002F mapActions transforma as actions em métodos do componente\n",[129,962,963],{"class":131,"line":274},[129,964,965],{"class":192},"    \u002F\u002F this.buscarUsuario(id) vai chamar store.dispatch('buscarUsuario', id)\n",[129,967,968,970,973,975,977,980,982,984,986,989,991],{"class":131,"line":292},[129,969,880],{"class":377},[129,971,972],{"class":180},"mapActions",[129,974,886],{"class":143},[129,976,734],{"class":153},[129,978,979],{"class":157},"buscarUsuario",[129,981,734],{"class":153},[129,983,362],{"class":139},[129,985,154],{"class":153},[129,987,988],{"class":157},"adicionarAoCarrinho",[129,990,734],{"class":153},[129,992,942],{"class":143},[129,994,995],{"class":131,"line":313},[129,996,799],{"class":139},[129,998,999],{"class":131,"line":319},[129,1000,1001],{"class":139},"}\n",[76,1003,1005],{"id":1004},"modules-escalando-com-vuex","Modules: escalando com Vuex",[11,1007,1008,1009,1012,1013,1015,1016,1015,1019,1022,1023,301],{},"Em projetos maiores, colocar tudo em um único arquivo de store rapidamente se torna inviável. O Vuex resolve isso com ",[84,1010,1011],{},"modules",": é possível dividir o store em fatias menores, cada uma com seu próprio ",[37,1014,284],{},", ",[37,1017,1018],{},"mutations",[37,1020,1021],{},"actions"," e ",[37,1024,1025],{},"getters",[120,1027,1029],{"className":122,"code":1028,"language":124,"meta":125,"style":125},"const moduloCarrinho = {\n  \u002F\u002F namespaced: true isola as mutations e actions deste módulo\n  \u002F\u002F sem isso, elas ficam no namespace global e podem colidir com outros módulos\n  namespaced: true,\n  state: () => ({ itens: [] }),\n  mutations: {\n    ADICIONAR(state, item) { state.itens.push(item) }\n  },\n  actions: {\n    \u002F\u002F para chamar esta action de um componente:\n    \u002F\u002F store.dispatch('carrinho\u002Fadicionar', item)\n    adicionar({ commit }, item) {\n      commit('ADICIONAR', item)\n    }\n  }\n}\n\nconst moduloUsuario = {\n  namespaced: true,\n  state: () => ({ dados: null }),\n  mutations: {\n    \u002F\u002F para chamar esta mutation:\n    \u002F\u002F store.commit('usuario\u002FSET', dados)\n    SET(state, usuario) { state.dados = usuario }\n  }\n}\n\nexport default createStore({\n  modules: {\n    carrinho: moduloCarrinho,\n    usuario: moduloUsuario\n  }\n})\n",[37,1030,1031,1043,1048,1053,1066,1097,1105,1142,1146,1154,1159,1164,1181,1200,1204,1208,1212,1216,1227,1237,1264,1272,1277,1282,1313,1317,1321,1325,1337,1346,1356,1365,1369],{"__ignoreMap":125},[129,1032,1033,1036,1039,1041],{"class":131,"line":132},[129,1034,1035],{"class":370},"const",[129,1037,1038],{"class":309}," moduloCarrinho",[129,1040,471],{"class":377},[129,1042,212],{"class":139},[129,1044,1045],{"class":131,"line":164},[129,1046,1047],{"class":192},"  \u002F\u002F namespaced: true isola as mutations e actions deste módulo\n",[129,1049,1050],{"class":131,"line":171},[129,1051,1052],{"class":192},"  \u002F\u002F sem isso, elas ficam no namespace global e podem colidir com outros módulos\n",[129,1054,1055,1058,1060,1064],{"class":131,"line":189},[129,1056,1057],{"class":205},"  namespaced",[129,1059,209],{"class":139},[129,1061,1063],{"class":1062},"sMrrN"," true",[129,1065,227],{"class":139},[129,1067,1068,1070,1072,1075,1077,1080,1083,1086,1088,1091,1093,1095],{"class":131,"line":196},[129,1069,206],{"class":180},[129,1071,209],{"class":139},[129,1073,1074],{"class":139}," ()",[129,1076,371],{"class":370},[129,1078,1079],{"class":143}," (",[129,1081,1082],{"class":139},"{",[129,1084,1085],{"class":205}," itens",[129,1087,209],{"class":139},[129,1089,1090],{"class":143}," [] ",[129,1092,805],{"class":139},[129,1094,287],{"class":143},[129,1096,227],{"class":139},[129,1098,1099,1101,1103],{"class":131,"line":202},[129,1100,434],{"class":205},[129,1102,209],{"class":139},[129,1104,212],{"class":139},[129,1106,1107,1110,1112,1114,1116,1118,1120,1122,1124,1126,1129,1131,1133,1135,1137,1140],{"class":131,"line":215},[129,1108,1109],{"class":277},"    ADICIONAR",[129,1111,183],{"class":139},[129,1113,284],{"class":283},[129,1115,362],{"class":139},[129,1117,365],{"class":283},[129,1119,287],{"class":139},[129,1121,140],{"class":139},[129,1123,298],{"class":143},[129,1125,301],{"class":139},[129,1127,1128],{"class":143},"itens",[129,1130,301],{"class":139},[129,1132,512],{"class":180},[129,1134,183],{"class":205},[129,1136,570],{"class":143},[129,1138,1139],{"class":205},") ",[129,1141,1001],{"class":139},[129,1143,1144],{"class":131,"line":230},[129,1145,244],{"class":139},[129,1147,1148,1150,1152],{"class":131,"line":241},[129,1149,625],{"class":205},[129,1151,209],{"class":139},[129,1153,212],{"class":139},[129,1155,1156],{"class":131,"line":247},[129,1157,1158],{"class":192},"    \u002F\u002F para chamar esta action de um componente:\n",[129,1160,1161],{"class":131,"line":252},[129,1162,1163],{"class":192},"    \u002F\u002F store.dispatch('carrinho\u002Fadicionar', item)\n",[129,1165,1166,1169,1171,1173,1175,1177,1179],{"class":131,"line":258},[129,1167,1168],{"class":277},"    adicionar",[129,1170,641],{"class":139},[129,1172,644],{"class":283},[129,1174,647],{"class":139},[129,1176,365],{"class":283},[129,1178,287],{"class":139},[129,1180,212],{"class":139},[129,1182,1183,1185,1187,1189,1192,1194,1196,1198],{"class":131,"line":264},[129,1184,729],{"class":180},[129,1186,183],{"class":205},[129,1188,734],{"class":153},[129,1190,1191],{"class":157},"ADICIONAR",[129,1193,734],{"class":153},[129,1195,362],{"class":139},[129,1197,365],{"class":143},[129,1199,394],{"class":205},[129,1201,1202],{"class":131,"line":274},[129,1203,400],{"class":139},[129,1205,1206],{"class":131,"line":292},[129,1207,799],{"class":139},[129,1209,1210],{"class":131,"line":313},[129,1211,1001],{"class":139},[129,1213,1214],{"class":131,"line":319},[129,1215,168],{"emptyLinePlaceholder":167},[129,1217,1218,1220,1223,1225],{"class":131,"line":333},[129,1219,1035],{"class":370},[129,1221,1222],{"class":309}," moduloUsuario",[129,1224,471],{"class":377},[129,1226,212],{"class":139},[129,1228,1229,1231,1233,1235],{"class":131,"line":339},[129,1230,1057],{"class":205},[129,1232,209],{"class":139},[129,1234,1063],{"class":1062},[129,1236,227],{"class":139},[129,1238,1239,1241,1243,1245,1247,1249,1251,1254,1256,1258,1260,1262],{"class":131,"line":397},[129,1240,206],{"class":180},[129,1242,209],{"class":139},[129,1244,1074],{"class":139},[129,1246,371],{"class":370},[129,1248,1079],{"class":143},[129,1250,1082],{"class":139},[129,1252,1253],{"class":205}," dados",[129,1255,209],{"class":139},[129,1257,224],{"class":223},[129,1259,147],{"class":139},[129,1261,287],{"class":143},[129,1263,227],{"class":139},[129,1265,1266,1268,1270],{"class":131,"line":403},[129,1267,434],{"class":205},[129,1269,209],{"class":139},[129,1271,212],{"class":139},[129,1273,1274],{"class":131,"line":408},[129,1275,1276],{"class":192},"    \u002F\u002F para chamar esta mutation:\n",[129,1278,1279],{"class":131,"line":413},[129,1280,1281],{"class":192},"    \u002F\u002F store.commit('usuario\u002FSET', dados)\n",[129,1283,1284,1287,1289,1291,1293,1295,1297,1299,1301,1303,1306,1308,1310],{"class":131,"line":419},[129,1285,1286],{"class":277},"    SET",[129,1288,183],{"class":139},[129,1290,284],{"class":283},[129,1292,362],{"class":139},[129,1294,453],{"class":283},[129,1296,287],{"class":139},[129,1298,140],{"class":139},[129,1300,298],{"class":143},[129,1302,301],{"class":139},[129,1304,1305],{"class":143},"dados",[129,1307,471],{"class":377},[129,1309,453],{"class":143},[129,1311,1312],{"class":139}," }\n",[129,1314,1315],{"class":131,"line":425},[129,1316,799],{"class":139},[129,1318,1319],{"class":131,"line":431},[129,1320,1001],{"class":139},[129,1322,1323],{"class":131,"line":441},[129,1324,168],{"emptyLinePlaceholder":167},[129,1326,1327,1329,1331,1333,1335],{"class":131,"line":460},[129,1328,174],{"class":135},[129,1330,177],{"class":135},[129,1332,144],{"class":180},[129,1334,183],{"class":143},[129,1336,186],{"class":139},[129,1338,1339,1342,1344],{"class":131,"line":477},[129,1340,1341],{"class":205},"  modules",[129,1343,209],{"class":139},[129,1345,212],{"class":139},[129,1347,1348,1350,1352,1354],{"class":131,"line":482},[129,1349,233],{"class":205},[129,1351,209],{"class":139},[129,1353,1038],{"class":143},[129,1355,227],{"class":139},[129,1357,1358,1360,1362],{"class":131,"line":501},[129,1359,218],{"class":205},[129,1361,209],{"class":139},[129,1363,1364],{"class":143}," moduloUsuario\n",[129,1366,1367],{"class":131,"line":522},[129,1368,799],{"class":139},[129,1370,1371,1373],{"class":131,"line":527},[129,1372,805],{"class":139},[129,1374,394],{"class":143},[11,1376,1377,1378,1381,1382,40,1385,1388],{},"Com ",[37,1379,1380],{},"namespaced: true",", as actions e mutations ficam acessíveis com o prefixo do módulo: ",[37,1383,1384],{},"dispatch('carrinho\u002Fadicionar', item)",[37,1386,1387],{},"commit('usuario\u002FSET', dados)",". Isso evita conflitos de nomes, mas adiciona uma camada de verbosidade que muitos desenvolvedores acham trabalhosa, especialmente em projetos com muitos módulos.",[76,1390,1392],{"id":1391},"pontos-fortes-do-vuex","Pontos fortes do Vuex",[11,1394,1395],{},"O Vuex tem uma estrutura muito bem definida, o que é uma vantagem real em equipes grandes. Quando todo mundo segue as mesmas regras (state só é alterado via mutations, lógica assíncrona vai em actions), o código fica previsível. É fácil auditar um bug rastreando qual mutation foi chamada, graças à integração com o Vue DevTools.",[11,1397,1398],{},"Além disso, a comunidade em torno do Vuex é imensa. Anos de produção geraram uma quantidade enorme de tutoriais, soluções no Stack Overflow e padrões documentados para praticamente qualquer cenário.",[76,1400,1402],{"id":1401},"fricções-que-o-vuex-carrega","Fricções que o Vuex carrega",[11,1404,1405,1406,1409,1410,1413],{},"A principal crítica ao Vuex é o ",[84,1407,1408],{},"boilerplate",". Para uma simples atualização de dados, você precisa: definir o estado, criar uma mutation, criar uma action que chama essa mutation, e então dentro do componente fazer ",[37,1411,1412],{},"dispatch"," da action. São muitas camadas para uma operação que, conceitualmente, é simples.",[11,1415,1416],{},"Outro ponto é a experiência com TypeScript. O Vuex foi projetado na era do Vue 2, antes de TypeScript se tornar central no ecossistema. Embora seja possível tipar o Vuex, isso exige configurações extras e workarounds que nunca foram elegantes. A inferência de tipos automática simplesmente não está lá.",[11,1418,1419,1420,1428,1429,1431,1432,1434],{},"Por fim, há uma dúvida clássica que assombra desenvolvedores Vuex: ",[15,1421,1422,1423,40,1425,1427],{},"devo usar ",[37,1424,114],{},[37,1426,1412],{},"?"," ",[37,1430,114],{}," chama mutations, ",[37,1433,1412],{}," chama actions. Parece simples, mas na prática isso gera confusão, especialmente para quem está aprendendo.",[23,1436],{},[26,1438,1440],{"id":1439},"pinia-o-futuro-do-gerenciamento-de-estado","Pinia: o futuro do gerenciamento de estado",[11,1442,1443],{},"O Pinia surgiu como um experimento em 2019, criado por Eduardo San Martin Morote, o mesmo membro do core team do Vue responsável pelo Vue Router. A ideia era reimaginar como um store Vue poderia funcionar com a Composition API em mente desde o primeiro dia.",[11,1445,1446,1447,1450],{},"O experimento deu tão certo que hoje o Pinia é a biblioteca de gerenciamento de estado ",[84,1448,1449],{},"oficialmente recomendada"," para Vue.js. A própria documentação do Vuex reconhece isso e orienta novos projetos a usarem Pinia. Evan You, criador do Vue, chegou a se referir ao Pinia como o que seria o Vuex 5.",[76,1452,1454],{"id":1453},"a-arquitetura-do-pinia","A arquitetura do Pinia",[11,1456,1457],{},"O Pinia simplifica o modelo do Vuex eliminando as mutations. O ciclo de vida do estado agora tem apenas três conceitos:",[11,1459,1460,1462],{},[84,1461,92],{}," continua sendo os dados da aplicação.",[11,1464,1465,1467],{},[84,1466,98],{}," continuam sendo propriedades computadas derivadas do estado.",[11,1469,1470,1472],{},[84,1471,110],{}," agora fazem tudo: lógica síncrona, assíncrona, e modificação direta do estado. Não existe mais a distinção entre mutation e action.",[11,1474,1475,1476,1479],{},"Além disso, o Pinia é ",[84,1477,1478],{},"modular por design",". Em vez de um único store global com módulos internos, você cria múltiplos stores independentes, um para cada domínio da sua aplicação.",[11,1481,1482],{},"Veja o equivalente do exemplo anterior, mas em Pinia:",[120,1484,1486],{"className":122,"code":1485,"language":124,"meta":125,"style":125},"import { defineStore } from 'pinia'\n\n\u002F\u002F defineStore recebe dois argumentos:\n\u002F\u002F 1. um ID único (string) que identifica o store na devtools e no sistema de reatividade\n\u002F\u002F 2. um objeto de configuração (ou uma função, como veremos no Setup Store)\n\u002F\u002F por convenção, o nome da função começa com \"use\" e termina com \"Store\"\nexport const useCarrinhoStore = defineStore('carrinho', {\n  \u002F\u002F state agora é uma função que retorna o objeto de dados\n  \u002F\u002F isso garante que cada instância da aplicação tenha seu próprio estado (importante para SSR)\n  state: () => ({\n    itens: []\n  }),\n\n  \u002F\u002F getters funcionam igual ao Vuex: recebem state e retornam um valor derivado\n  getters: {\n    totalItens: (state) => state.itens.length,\n    totalValor: (state) => state.itens.reduce((acc, item) => acc + item.preco, 0)\n  },\n\n  \u002F\u002F actions aqui fazem TUDO: lógica síncrona, assíncrona e modificação de estado\n  \u002F\u002F não existe mais a separação entre mutation (síncrono) e action (assíncrono)\n  \u002F\u002F dentro das actions, \"this\" se refere ao próprio store\n  actions: {\n    adicionar(produto) {\n      this.itens.push(produto) \u002F\u002F modificação direta, sem commit!\n    },\n    remover(produtoId) {\n      this.itens = this.itens.filter(item => item.id !== produtoId)\n    }\n  }\n})\n\n\u002F\u002F cada domínio da aplicação tem seu próprio store independente\n\u002F\u002F não precisamos de módulos aninhados como no Vuex\nexport const useUsuarioStore = defineStore('usuario', {\n  state: () => ({\n    dados: null\n  }),\n  actions: {\n    async buscar(userId) {\n      const response = await fetch(`\u002Fapi\u002Fusuarios\u002F${userId}`)\n      \u002F\u002F modificação direta do state dentro da action, sem intermediário\n      this.dados = await response.json()\n    }\n  }\n})\n",[37,1487,1488,1508,1512,1517,1522,1527,1532,1558,1563,1568,1582,1591,1600,1604,1609,1617,1644,1700,1704,1708,1713,1718,1723,1731,1743,1765,1769,1783,1822,1826,1830,1836,1840,1845,1850,1875,1889,1899,1907,1915,1930,1956,1961,1981,1985,1989],{"__ignoreMap":125},[129,1489,1490,1492,1494,1497,1499,1501,1503,1506],{"class":131,"line":132},[129,1491,136],{"class":135},[129,1493,140],{"class":139},[129,1495,1496],{"class":143}," defineStore",[129,1498,147],{"class":139},[129,1500,150],{"class":135},[129,1502,154],{"class":153},[129,1504,1505],{"class":157},"pinia",[129,1507,161],{"class":153},[129,1509,1510],{"class":131,"line":164},[129,1511,168],{"emptyLinePlaceholder":167},[129,1513,1514],{"class":131,"line":171},[129,1515,1516],{"class":192},"\u002F\u002F defineStore recebe dois argumentos:\n",[129,1518,1519],{"class":131,"line":189},[129,1520,1521],{"class":192},"\u002F\u002F 1. um ID único (string) que identifica o store na devtools e no sistema de reatividade\n",[129,1523,1524],{"class":131,"line":196},[129,1525,1526],{"class":192},"\u002F\u002F 2. um objeto de configuração (ou uma função, como veremos no Setup Store)\n",[129,1528,1529],{"class":131,"line":202},[129,1530,1531],{"class":192},"\u002F\u002F por convenção, o nome da função começa com \"use\" e termina com \"Store\"\n",[129,1533,1534,1536,1539,1542,1544,1546,1548,1550,1552,1554,1556],{"class":131,"line":215},[129,1535,174],{"class":135},[129,1537,1538],{"class":370}," const",[129,1540,1541],{"class":309}," useCarrinhoStore",[129,1543,471],{"class":377},[129,1545,1496],{"class":180},[129,1547,183],{"class":143},[129,1549,734],{"class":153},[129,1551,304],{"class":157},[129,1553,734],{"class":153},[129,1555,362],{"class":139},[129,1557,212],{"class":139},[129,1559,1560],{"class":131,"line":230},[129,1561,1562],{"class":192},"  \u002F\u002F state agora é uma função que retorna o objeto de dados\n",[129,1564,1565],{"class":131,"line":241},[129,1566,1567],{"class":192},"  \u002F\u002F isso garante que cada instância da aplicação tenha seu próprio estado (importante para SSR)\n",[129,1569,1570,1572,1574,1576,1578,1580],{"class":131,"line":247},[129,1571,206],{"class":180},[129,1573,209],{"class":139},[129,1575,1074],{"class":139},[129,1577,371],{"class":370},[129,1579,1079],{"class":143},[129,1581,186],{"class":139},[129,1583,1584,1587,1589],{"class":131,"line":252},[129,1585,1586],{"class":205},"    itens",[129,1588,209],{"class":139},[129,1590,238],{"class":143},[129,1592,1593,1596,1598],{"class":131,"line":258},[129,1594,1595],{"class":139},"  }",[129,1597,287],{"class":143},[129,1599,227],{"class":139},[129,1601,1602],{"class":131,"line":264},[129,1603,168],{"emptyLinePlaceholder":167},[129,1605,1606],{"class":131,"line":274},[129,1607,1608],{"class":192},"  \u002F\u002F getters funcionam igual ao Vuex: recebem state e retornam um valor derivado\n",[129,1610,1611,1613,1615],{"class":131,"line":292},[129,1612,267],{"class":205},[129,1614,209],{"class":139},[129,1616,212],{"class":139},[129,1618,1619,1621,1623,1625,1627,1629,1631,1633,1635,1637,1639,1642],{"class":131,"line":313},[129,1620,278],{"class":180},[129,1622,209],{"class":139},[129,1624,1079],{"class":139},[129,1626,284],{"class":283},[129,1628,287],{"class":139},[129,1630,371],{"class":370},[129,1632,298],{"class":143},[129,1634,301],{"class":139},[129,1636,1128],{"class":143},[129,1638,301],{"class":139},[129,1640,1641],{"class":309},"length",[129,1643,227],{"class":139},[129,1645,1646,1648,1650,1652,1654,1656,1658,1660,1662,1664,1666,1668,1670,1672,1674,1676,1678,1680,1682,1685,1688,1690,1692,1694,1696,1698],{"class":131,"line":319},[129,1647,322],{"class":180},[129,1649,209],{"class":139},[129,1651,1079],{"class":139},[129,1653,284],{"class":283},[129,1655,287],{"class":139},[129,1657,371],{"class":370},[129,1659,298],{"class":143},[129,1661,301],{"class":139},[129,1663,1128],{"class":143},[129,1665,301],{"class":139},[129,1667,352],{"class":180},[129,1669,183],{"class":143},[129,1671,183],{"class":139},[129,1673,359],{"class":283},[129,1675,362],{"class":139},[129,1677,365],{"class":283},[129,1679,287],{"class":139},[129,1681,371],{"class":370},[129,1683,1684],{"class":143}," acc ",[129,1686,1687],{"class":377},"+",[129,1689,365],{"class":143},[129,1691,301],{"class":139},[129,1693,385],{"class":143},[129,1695,362],{"class":139},[129,1697,391],{"class":390},[129,1699,394],{"class":143},[129,1701,1702],{"class":131,"line":333},[129,1703,244],{"class":139},[129,1705,1706],{"class":131,"line":339},[129,1707,168],{"emptyLinePlaceholder":167},[129,1709,1710],{"class":131,"line":397},[129,1711,1712],{"class":192},"  \u002F\u002F actions aqui fazem TUDO: lógica síncrona, assíncrona e modificação de estado\n",[129,1714,1715],{"class":131,"line":403},[129,1716,1717],{"class":192},"  \u002F\u002F não existe mais a separação entre mutation (síncrono) e action (assíncrono)\n",[129,1719,1720],{"class":131,"line":408},[129,1721,1722],{"class":192},"  \u002F\u002F dentro das actions, \"this\" se refere ao próprio store\n",[129,1724,1725,1727,1729],{"class":131,"line":413},[129,1726,625],{"class":205},[129,1728,209],{"class":139},[129,1730,212],{"class":139},[129,1732,1733,1735,1737,1739,1741],{"class":131,"line":419},[129,1734,1168],{"class":277},[129,1736,183],{"class":139},[129,1738,517],{"class":283},[129,1740,287],{"class":139},[129,1742,212],{"class":139},[129,1744,1745,1748,1750,1752,1754,1756,1758,1760,1762],{"class":131,"line":425},[129,1746,1747],{"class":223},"      this",[129,1749,301],{"class":139},[129,1751,1128],{"class":143},[129,1753,301],{"class":139},[129,1755,512],{"class":180},[129,1757,183],{"class":205},[129,1759,517],{"class":143},[129,1761,1139],{"class":205},[129,1763,1764],{"class":192},"\u002F\u002F modificação direta, sem commit!\n",[129,1766,1767],{"class":131,"line":431},[129,1768,316],{"class":139},[129,1770,1771,1774,1776,1779,1781],{"class":131,"line":441},[129,1772,1773],{"class":277},"    remover",[129,1775,183],{"class":139},[129,1777,1778],{"class":283},"produtoId",[129,1780,287],{"class":139},[129,1782,212],{"class":139},[129,1784,1785,1787,1789,1791,1793,1796,1798,1800,1802,1804,1806,1808,1810,1812,1814,1816,1818,1820],{"class":131,"line":460},[129,1786,1747],{"class":223},[129,1788,301],{"class":139},[129,1790,1128],{"class":143},[129,1792,471],{"class":377},[129,1794,1795],{"class":223}," this",[129,1797,301],{"class":139},[129,1799,1128],{"class":143},[129,1801,301],{"class":139},[129,1803,565],{"class":180},[129,1805,183],{"class":205},[129,1807,570],{"class":283},[129,1809,371],{"class":370},[129,1811,365],{"class":143},[129,1813,301],{"class":139},[129,1815,579],{"class":143},[129,1817,582],{"class":377},[129,1819,539],{"class":143},[129,1821,394],{"class":205},[129,1823,1824],{"class":131,"line":477},[129,1825,400],{"class":139},[129,1827,1828],{"class":131,"line":482},[129,1829,799],{"class":139},[129,1831,1832,1834],{"class":131,"line":501},[129,1833,805],{"class":139},[129,1835,394],{"class":143},[129,1837,1838],{"class":131,"line":522},[129,1839,168],{"emptyLinePlaceholder":167},[129,1841,1842],{"class":131,"line":527},[129,1843,1844],{"class":192},"\u002F\u002F cada domínio da aplicação tem seu próprio store independente\n",[129,1846,1847],{"class":131,"line":546},[129,1848,1849],{"class":192},"\u002F\u002F não precisamos de módulos aninhados como no Vuex\n",[129,1851,1852,1854,1856,1859,1861,1863,1865,1867,1869,1871,1873],{"class":131,"line":589},[129,1853,174],{"class":135},[129,1855,1538],{"class":370},[129,1857,1858],{"class":309}," useUsuarioStore",[129,1860,471],{"class":377},[129,1862,1496],{"class":180},[129,1864,183],{"class":143},[129,1866,734],{"class":153},[129,1868,468],{"class":157},[129,1870,734],{"class":153},[129,1872,362],{"class":139},[129,1874,212],{"class":139},[129,1876,1877,1879,1881,1883,1885,1887],{"class":131,"line":594},[129,1878,206],{"class":180},[129,1880,209],{"class":139},[129,1882,1074],{"class":139},[129,1884,371],{"class":370},[129,1886,1079],{"class":143},[129,1888,186],{"class":139},[129,1890,1891,1894,1896],{"class":131,"line":599},[129,1892,1893],{"class":205},"    dados",[129,1895,209],{"class":139},[129,1897,1898],{"class":223}," null\n",[129,1900,1901,1903,1905],{"class":131,"line":604},[129,1902,1595],{"class":139},[129,1904,287],{"class":143},[129,1906,227],{"class":139},[129,1908,1909,1911,1913],{"class":131,"line":610},[129,1910,625],{"class":205},[129,1912,209],{"class":139},[129,1914,212],{"class":139},[129,1916,1917,1919,1922,1924,1926,1928],{"class":131,"line":616},[129,1918,635],{"class":370},[129,1920,1921],{"class":277}," buscar",[129,1923,183],{"class":139},[129,1925,685],{"class":283},[129,1927,287],{"class":139},[129,1929,212],{"class":139},[129,1931,1932,1934,1936,1938,1940,1942,1944,1946,1948,1950,1952,1954],{"class":131,"line":622},[129,1933,660],{"class":370},[129,1935,663],{"class":309},[129,1937,471],{"class":377},[129,1939,668],{"class":135},[129,1941,671],{"class":180},[129,1943,183],{"class":205},[129,1945,676],{"class":153},[129,1947,679],{"class":157},[129,1949,682],{"class":153},[129,1951,685],{"class":143},[129,1953,688],{"class":153},[129,1955,394],{"class":205},[129,1957,1958],{"class":131,"line":632},[129,1959,1960],{"class":192},"      \u002F\u002F modificação direta do state dentro da action, sem intermediário\n",[129,1962,1963,1965,1967,1969,1971,1973,1975,1977,1979],{"class":131,"line":657},[129,1964,1747],{"class":223},[129,1966,301],{"class":139},[129,1968,1305],{"class":143},[129,1970,471],{"class":377},[129,1972,668],{"class":135},[129,1974,663],{"class":143},[129,1976,301],{"class":139},[129,1978,708],{"class":180},[129,1980,711],{"class":205},[129,1982,1983],{"class":131,"line":693},[129,1984,400],{"class":139},[129,1986,1987],{"class":131,"line":714},[129,1988,799],{"class":139},[129,1990,1991,1993],{"class":131,"line":720},[129,1992,805],{"class":139},[129,1994,394],{"class":143},[11,1996,1997,1998,209],{},"E consumindo dentro de um componente com ",[37,1999,2000],{},"\u003Cscript setup>",[120,2002,2006],{"className":2003,"code":2004,"language":2005,"meta":125,"style":125},"language-vue shiki shiki-themes material-theme-lighter github-dark github-dark","\u003Cscript setup>\nimport { useCarrinhoStore } from '@\u002Fstores\u002Fcarrinho'\nimport { useUsuarioStore } from '@\u002Fstores\u002Fusuario'\n\n\u002F\u002F chamar o composable retorna a instância reativa do store\n\u002F\u002F sem mapState, sem mapGetters, sem mapActions\n\u002F\u002F state, getters e actions ficam acessíveis diretamente no objeto\nconst carrinho = useCarrinhoStore()\nconst usuario = useUsuarioStore()\n\n\u002F\u002F chamar uma action é tão simples quanto chamar um método normal\ncarrinho.adicionar({ id: 1, nome: 'Produto', preco: 99.90 })\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cdiv>\n    \u003C!-- getters acessados diretamente, sem nenhum helper -->\n    \u003Cp>Itens no carrinho: {{ carrinho.totalItens }}\u003C\u002Fp>\n    \u003Cp>Total: R$ {{ carrinho.totalValor.toFixed(2) }}\u003C\u002Fp>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n","vue",[37,2007,2008,2024,2043,2062,2066,2071,2076,2081,2094,2106,2110,2115,2164,2173,2177,2186,2196,2201,2220,2237,2246],{"__ignoreMap":125},[129,2009,2010,2013,2017,2021],{"class":131,"line":132},[129,2011,2012],{"class":139},"\u003C",[129,2014,2016],{"class":2015},"sqIbZ","script",[129,2018,2020],{"class":2019},"s7047"," setup",[129,2022,2023],{"class":139},">\n",[129,2025,2026,2028,2030,2032,2034,2036,2038,2041],{"class":131,"line":164},[129,2027,136],{"class":135},[129,2029,140],{"class":139},[129,2031,1541],{"class":143},[129,2033,147],{"class":139},[129,2035,150],{"class":135},[129,2037,154],{"class":153},[129,2039,2040],{"class":157},"@\u002Fstores\u002Fcarrinho",[129,2042,161],{"class":153},[129,2044,2045,2047,2049,2051,2053,2055,2057,2060],{"class":131,"line":171},[129,2046,136],{"class":135},[129,2048,140],{"class":139},[129,2050,1858],{"class":143},[129,2052,147],{"class":139},[129,2054,150],{"class":135},[129,2056,154],{"class":153},[129,2058,2059],{"class":157},"@\u002Fstores\u002Fusuario",[129,2061,161],{"class":153},[129,2063,2064],{"class":131,"line":189},[129,2065,168],{"emptyLinePlaceholder":167},[129,2067,2068],{"class":131,"line":196},[129,2069,2070],{"class":192},"\u002F\u002F chamar o composable retorna a instância reativa do store\n",[129,2072,2073],{"class":131,"line":202},[129,2074,2075],{"class":192},"\u002F\u002F sem mapState, sem mapGetters, sem mapActions\n",[129,2077,2078],{"class":131,"line":215},[129,2079,2080],{"class":192},"\u002F\u002F state, getters e actions ficam acessíveis diretamente no objeto\n",[129,2082,2083,2085,2088,2090,2092],{"class":131,"line":230},[129,2084,1035],{"class":370},[129,2086,2087],{"class":309}," carrinho",[129,2089,471],{"class":377},[129,2091,1541],{"class":180},[129,2093,711],{"class":143},[129,2095,2096,2098,2100,2102,2104],{"class":131,"line":241},[129,2097,1035],{"class":370},[129,2099,453],{"class":309},[129,2101,471],{"class":377},[129,2103,1858],{"class":180},[129,2105,711],{"class":143},[129,2107,2108],{"class":131,"line":247},[129,2109,168],{"emptyLinePlaceholder":167},[129,2111,2112],{"class":131,"line":252},[129,2113,2114],{"class":192},"\u002F\u002F chamar uma action é tão simples quanto chamar um método normal\n",[129,2116,2117,2119,2121,2124,2126,2128,2131,2133,2136,2138,2141,2143,2145,2148,2150,2152,2155,2157,2160,2162],{"class":131,"line":258},[129,2118,304],{"class":143},[129,2120,301],{"class":139},[129,2122,2123],{"class":180},"adicionar",[129,2125,183],{"class":143},[129,2127,1082],{"class":139},[129,2129,2130],{"class":205}," id",[129,2132,209],{"class":139},[129,2134,2135],{"class":390}," 1",[129,2137,362],{"class":139},[129,2139,2140],{"class":205}," nome",[129,2142,209],{"class":139},[129,2144,154],{"class":153},[129,2146,2147],{"class":157},"Produto",[129,2149,734],{"class":153},[129,2151,362],{"class":139},[129,2153,2154],{"class":205}," preco",[129,2156,209],{"class":139},[129,2158,2159],{"class":390}," 99.90",[129,2161,147],{"class":139},[129,2163,394],{"class":143},[129,2165,2166,2169,2171],{"class":131,"line":264},[129,2167,2168],{"class":139},"\u003C\u002F",[129,2170,2016],{"class":2015},[129,2172,2023],{"class":139},[129,2174,2175],{"class":131,"line":274},[129,2176,168],{"emptyLinePlaceholder":167},[129,2178,2179,2181,2184],{"class":131,"line":292},[129,2180,2012],{"class":139},[129,2182,2183],{"class":2015},"template",[129,2185,2023],{"class":139},[129,2187,2188,2191,2194],{"class":131,"line":313},[129,2189,2190],{"class":139},"  \u003C",[129,2192,2193],{"class":2015},"div",[129,2195,2023],{"class":139},[129,2197,2198],{"class":131,"line":319},[129,2199,2200],{"class":192},"    \u003C!-- getters acessados diretamente, sem nenhum helper -->\n",[129,2202,2203,2206,2208,2211,2214,2216,2218],{"class":131,"line":333},[129,2204,2205],{"class":139},"    \u003C",[129,2207,11],{"class":2015},[129,2209,2210],{"class":139},">",[129,2212,2213],{"class":143},"Itens no carrinho: {{ carrinho.totalItens }}",[129,2215,2168],{"class":139},[129,2217,11],{"class":2015},[129,2219,2023],{"class":139},[129,2221,2222,2224,2226,2228,2231,2233,2235],{"class":131,"line":339},[129,2223,2205],{"class":139},[129,2225,11],{"class":2015},[129,2227,2210],{"class":139},[129,2229,2230],{"class":143},"Total: R$ {{ carrinho.totalValor.toFixed(2) }}",[129,2232,2168],{"class":139},[129,2234,11],{"class":2015},[129,2236,2023],{"class":139},[129,2238,2239,2242,2244],{"class":131,"line":397},[129,2240,2241],{"class":139},"  \u003C\u002F",[129,2243,2193],{"class":2015},[129,2245,2023],{"class":139},[129,2247,2248,2250,2252],{"class":131,"line":403},[129,2249,2168],{"class":139},[129,2251,2183],{"class":2015},[129,2253,2023],{"class":139},[11,2255,2256,2257,1015,2259,40,2261,2263],{},"Perceba o quanto o código fica mais limpo. Não há necessidade de ",[37,2258,883],{},[37,2260,921],{},[37,2262,972],{},". Você importa o store, chama a função composable, e acessa estado, getters e actions diretamente.",[76,2265,2267],{"id":2266},"o-estilo-setup-store-máxima-flexibilidade","O estilo Setup Store: máxima flexibilidade",[11,2269,2270,2271,2274,2275,2278,2279,1015,2282,2285,2286,2290],{},"Além da API de objeto (parecida com o estilo Options do Vue), o Pinia também oferece um estilo baseado na Composition API chamado ",[84,2272,2273],{},"Setup Store",". Ele funciona exatamente como um ",[37,2276,2277],{},"setup()",", usando ",[37,2280,2281],{},"ref",[37,2283,2284],{},"computed"," e funções normais. Por baixo dos panos, o mecanismo que mantém o estado vivo entre chamadas é o mesmo de uma ",[59,2287,2289],{"href":61,"rel":2288},[63],"closure",": o ambiente criado quando o store é inicializado persiste enquanto a aplicação estiver rodando, e as funções expostas continuam com acesso a ele.",[120,2292,2294],{"className":122,"code":2293,"language":124,"meta":125,"style":125},"import { ref, computed } from 'vue'\nimport { defineStore } from 'pinia'\n\n\u002F\u002F no Setup Store, o segundo argumento é uma função (como o setup() de um componente)\n\u002F\u002F em vez de um objeto com state\u002Fgetters\u002Factions\nexport const useCarrinhoStore = defineStore('carrinho', () => {\n  \u002F\u002F ref() => equivale ao \"state\" no Options Store\n  const itens = ref([])\n\n  \u002F\u002F computed() => equivale aos \"getters\"\n  const totalItens = computed(() => itens.value.length)\n  const totalValor = computed(() =>\n    itens.value.reduce((acc, item) => acc + item.preco, 0)\n  )\n\n  \u002F\u002F funções normais => equivalem às \"actions\"\n  function adicionar(produto) {\n    itens.value.push(produto)\n  }\n\n  function remover(produtoId) {\n    itens.value = itens.value.filter(item => item.id !== produtoId)\n  }\n\n  \u002F\u002F tudo que for retornado aqui fica acessível publicamente no store\n  \u002F\u002F o que não for retornado fica encapsulado (útil para lógica interna privada)\n  return { itens, totalItens, totalValor, adicionar, remover }\n})\n",[37,2295,2296,2320,2338,2342,2347,2352,2380,2385,2399,2403,2408,2439,2457,2499,2504,2508,2513,2529,2547,2551,2555,2570,2608,2612,2616,2621,2626,2653],{"__ignoreMap":125},[129,2297,2298,2300,2302,2305,2307,2310,2312,2314,2316,2318],{"class":131,"line":132},[129,2299,136],{"class":135},[129,2301,140],{"class":139},[129,2303,2304],{"class":143}," ref",[129,2306,362],{"class":139},[129,2308,2309],{"class":143}," computed",[129,2311,147],{"class":139},[129,2313,150],{"class":135},[129,2315,154],{"class":153},[129,2317,2005],{"class":157},[129,2319,161],{"class":153},[129,2321,2322,2324,2326,2328,2330,2332,2334,2336],{"class":131,"line":164},[129,2323,136],{"class":135},[129,2325,140],{"class":139},[129,2327,1496],{"class":143},[129,2329,147],{"class":139},[129,2331,150],{"class":135},[129,2333,154],{"class":153},[129,2335,1505],{"class":157},[129,2337,161],{"class":153},[129,2339,2340],{"class":131,"line":171},[129,2341,168],{"emptyLinePlaceholder":167},[129,2343,2344],{"class":131,"line":189},[129,2345,2346],{"class":192},"\u002F\u002F no Setup Store, o segundo argumento é uma função (como o setup() de um componente)\n",[129,2348,2349],{"class":131,"line":196},[129,2350,2351],{"class":192},"\u002F\u002F em vez de um objeto com state\u002Fgetters\u002Factions\n",[129,2353,2354,2356,2358,2360,2362,2364,2366,2368,2370,2372,2374,2376,2378],{"class":131,"line":202},[129,2355,174],{"class":135},[129,2357,1538],{"class":370},[129,2359,1541],{"class":309},[129,2361,471],{"class":377},[129,2363,1496],{"class":180},[129,2365,183],{"class":143},[129,2367,734],{"class":153},[129,2369,304],{"class":157},[129,2371,734],{"class":153},[129,2373,362],{"class":139},[129,2375,1074],{"class":139},[129,2377,371],{"class":370},[129,2379,212],{"class":139},[129,2381,2382],{"class":131,"line":215},[129,2383,2384],{"class":192},"  \u002F\u002F ref() => equivale ao \"state\" no Options Store\n",[129,2386,2387,2390,2392,2394,2396],{"class":131,"line":230},[129,2388,2389],{"class":370},"  const",[129,2391,1085],{"class":309},[129,2393,471],{"class":377},[129,2395,2304],{"class":180},[129,2397,2398],{"class":205},"([])\n",[129,2400,2401],{"class":131,"line":241},[129,2402,168],{"emptyLinePlaceholder":167},[129,2404,2405],{"class":131,"line":247},[129,2406,2407],{"class":192},"  \u002F\u002F computed() => equivale aos \"getters\"\n",[129,2409,2410,2412,2415,2417,2419,2421,2424,2426,2428,2430,2433,2435,2437],{"class":131,"line":252},[129,2411,2389],{"class":370},[129,2413,2414],{"class":309}," totalItens",[129,2416,471],{"class":377},[129,2418,2309],{"class":180},[129,2420,183],{"class":205},[129,2422,2423],{"class":139},"()",[129,2425,371],{"class":370},[129,2427,1085],{"class":143},[129,2429,301],{"class":139},[129,2431,2432],{"class":143},"value",[129,2434,301],{"class":139},[129,2436,1641],{"class":309},[129,2438,394],{"class":205},[129,2440,2441,2443,2446,2448,2450,2452,2454],{"class":131,"line":258},[129,2442,2389],{"class":370},[129,2444,2445],{"class":309}," totalValor",[129,2447,471],{"class":377},[129,2449,2309],{"class":180},[129,2451,183],{"class":205},[129,2453,2423],{"class":139},[129,2455,2456],{"class":370}," =>\n",[129,2458,2459,2461,2463,2465,2467,2469,2471,2473,2475,2477,2479,2481,2483,2485,2487,2489,2491,2493,2495,2497],{"class":131,"line":264},[129,2460,1586],{"class":143},[129,2462,301],{"class":139},[129,2464,2432],{"class":143},[129,2466,301],{"class":139},[129,2468,352],{"class":180},[129,2470,183],{"class":205},[129,2472,183],{"class":139},[129,2474,359],{"class":283},[129,2476,362],{"class":139},[129,2478,365],{"class":283},[129,2480,287],{"class":139},[129,2482,371],{"class":370},[129,2484,374],{"class":143},[129,2486,378],{"class":377},[129,2488,365],{"class":143},[129,2490,301],{"class":139},[129,2492,385],{"class":143},[129,2494,362],{"class":139},[129,2496,391],{"class":390},[129,2498,394],{"class":205},[129,2500,2501],{"class":131,"line":274},[129,2502,2503],{"class":205},"  )\n",[129,2505,2506],{"class":131,"line":292},[129,2507,168],{"emptyLinePlaceholder":167},[129,2509,2510],{"class":131,"line":313},[129,2511,2512],{"class":192},"  \u002F\u002F funções normais => equivalem às \"actions\"\n",[129,2514,2515,2518,2521,2523,2525,2527],{"class":131,"line":319},[129,2516,2517],{"class":370},"  function",[129,2519,2520],{"class":180}," adicionar",[129,2522,183],{"class":139},[129,2524,517],{"class":283},[129,2526,287],{"class":139},[129,2528,212],{"class":139},[129,2530,2531,2533,2535,2537,2539,2541,2543,2545],{"class":131,"line":333},[129,2532,1586],{"class":143},[129,2534,301],{"class":139},[129,2536,2432],{"class":143},[129,2538,301],{"class":139},[129,2540,512],{"class":180},[129,2542,183],{"class":205},[129,2544,517],{"class":143},[129,2546,394],{"class":205},[129,2548,2549],{"class":131,"line":339},[129,2550,799],{"class":139},[129,2552,2553],{"class":131,"line":397},[129,2554,168],{"emptyLinePlaceholder":167},[129,2556,2557,2559,2562,2564,2566,2568],{"class":131,"line":403},[129,2558,2517],{"class":370},[129,2560,2561],{"class":180}," remover",[129,2563,183],{"class":139},[129,2565,1778],{"class":283},[129,2567,287],{"class":139},[129,2569,212],{"class":139},[129,2571,2572,2574,2576,2578,2580,2582,2584,2586,2588,2590,2592,2594,2596,2598,2600,2602,2604,2606],{"class":131,"line":408},[129,2573,1586],{"class":143},[129,2575,301],{"class":139},[129,2577,2432],{"class":143},[129,2579,471],{"class":377},[129,2581,1085],{"class":143},[129,2583,301],{"class":139},[129,2585,2432],{"class":143},[129,2587,301],{"class":139},[129,2589,565],{"class":180},[129,2591,183],{"class":205},[129,2593,570],{"class":283},[129,2595,371],{"class":370},[129,2597,365],{"class":143},[129,2599,301],{"class":139},[129,2601,579],{"class":143},[129,2603,582],{"class":377},[129,2605,539],{"class":143},[129,2607,394],{"class":205},[129,2609,2610],{"class":131,"line":413},[129,2611,799],{"class":139},[129,2613,2614],{"class":131,"line":419},[129,2615,168],{"emptyLinePlaceholder":167},[129,2617,2618],{"class":131,"line":425},[129,2619,2620],{"class":192},"  \u002F\u002F tudo que for retornado aqui fica acessível publicamente no store\n",[129,2622,2623],{"class":131,"line":431},[129,2624,2625],{"class":192},"  \u002F\u002F o que não for retornado fica encapsulado (útil para lógica interna privada)\n",[129,2627,2628,2631,2633,2635,2637,2639,2641,2643,2645,2647,2649,2651],{"class":131,"line":441},[129,2629,2630],{"class":135},"  return",[129,2632,140],{"class":139},[129,2634,1085],{"class":143},[129,2636,362],{"class":139},[129,2638,2414],{"class":143},[129,2640,362],{"class":139},[129,2642,2445],{"class":143},[129,2644,362],{"class":139},[129,2646,2520],{"class":143},[129,2648,362],{"class":139},[129,2650,2561],{"class":143},[129,2652,1312],{"class":139},[129,2654,2655,2657],{"class":131,"line":460},[129,2656,805],{"class":139},[129,2658,394],{"class":143},[11,2660,2661,2662,2665,2666,2671],{},"Esse estilo é especialmente poderoso porque permite reutilizar composables dentro do store, compartilhar lógica entre stores com facilidade, e escrever um código que se parece exatamente com um composable Vue comum. Se você quiser ver um exemplo real do Setup Store em um projeto Nuxt 3, escrevi sobre como a ",[37,2663,2664],{},"useEditorStore"," foi estruturada no ",[59,2667,2670],{"href":2668,"rel":2669},"https:\u002F\u002Flarisantos.vercel.app\u002Fblog\u002Fvisitcard-generator-nuxt-pdf-do-zero",[63],"VisitCardGenerator",", um gerador de cartões de visita em PDF construído do zero com Nuxt 3 e Pinia.",[76,2673,2675],{"id":2674},"typescript-nativo","TypeScript nativo",[11,2677,2678],{},"Uma das maiores vantagens do Pinia é o suporte a TypeScript sem nenhuma configuração adicional. Os tipos são inferidos automaticamente a partir do estado definido. Você não precisa criar interfaces manualmente para o store, nem usar plugins ou hacks para ter autocomplete funcionando:",[120,2680,2684],{"className":2681,"code":2682,"language":2683,"meta":125,"style":125},"language-ts shiki shiki-themes material-theme-lighter github-dark github-dark","import { defineStore } from 'pinia'\n\n\u002F\u002F interface TypeScript definindo o formato de um produto\n\u002F\u002F o Pinia vai usar isso para inferir os tipos automaticamente\ninterface Produto {\n  id: number\n  nome: string\n  preco: number\n}\n\nexport const useCarrinhoStore = defineStore('carrinho', {\n  state: () => ({\n    \u002F\u002F \"as Produto[]\" diz ao TypeScript que este array só aceita objetos do tipo Produto\n    \u002F\u002F a partir daqui, toda a store tem inferência de tipos automática\n    itens: [] as Produto[]\n  }),\n  getters: {\n    \u002F\u002F a anotação \": number\" é necessária aqui por conta de uma limitação do TS\n    \u002F\u002F quando o getter referencia outro getter via \"this\" — neste caso é boa prática anotar\n    totalValor: (state): number =>\n      state.itens.reduce((acc, item) => acc + item.preco, 0)\n  },\n  actions: {\n    \u002F\u002F TypeScript já sabe que \"produto\" deve ser do tipo Produto\n    \u002F\u002F se você tentar passar um objeto sem o campo \"preco\", o editor vai reclamar\n    adicionar(produto: Produto) {\n      this.itens.push(produto)\n    }\n  }\n})\n","ts",[37,2685,2686,2704,2708,2713,2718,2729,2741,2751,2760,2764,2768,2792,2806,2811,2816,2832,2840,2848,2853,2858,2877,2919,2923,2931,2936,2941,2957,2975,2979,2983],{"__ignoreMap":125},[129,2687,2688,2690,2692,2694,2696,2698,2700,2702],{"class":131,"line":132},[129,2689,136],{"class":135},[129,2691,140],{"class":139},[129,2693,1496],{"class":143},[129,2695,147],{"class":139},[129,2697,150],{"class":135},[129,2699,154],{"class":153},[129,2701,1505],{"class":157},[129,2703,161],{"class":153},[129,2705,2706],{"class":131,"line":164},[129,2707,168],{"emptyLinePlaceholder":167},[129,2709,2710],{"class":131,"line":171},[129,2711,2712],{"class":192},"\u002F\u002F interface TypeScript definindo o formato de um produto\n",[129,2714,2715],{"class":131,"line":189},[129,2716,2717],{"class":192},"\u002F\u002F o Pinia vai usar isso para inferir os tipos automaticamente\n",[129,2719,2720,2723,2727],{"class":131,"line":196},[129,2721,2722],{"class":370},"interface",[129,2724,2726],{"class":2725},"soiBB"," Produto",[129,2728,212],{"class":139},[129,2730,2731,2735,2737],{"class":131,"line":202},[129,2732,2734],{"class":2733},"sTbKH","  id",[129,2736,209],{"class":377},[129,2738,2740],{"class":2739},"s3afY"," number\n",[129,2742,2743,2746,2748],{"class":131,"line":215},[129,2744,2745],{"class":2733},"  nome",[129,2747,209],{"class":377},[129,2749,2750],{"class":2739}," string\n",[129,2752,2753,2756,2758],{"class":131,"line":230},[129,2754,2755],{"class":2733},"  preco",[129,2757,209],{"class":377},[129,2759,2740],{"class":2739},[129,2761,2762],{"class":131,"line":241},[129,2763,1001],{"class":139},[129,2765,2766],{"class":131,"line":247},[129,2767,168],{"emptyLinePlaceholder":167},[129,2769,2770,2772,2774,2776,2778,2780,2782,2784,2786,2788,2790],{"class":131,"line":252},[129,2771,174],{"class":135},[129,2773,1538],{"class":370},[129,2775,1541],{"class":309},[129,2777,471],{"class":377},[129,2779,1496],{"class":180},[129,2781,183],{"class":143},[129,2783,734],{"class":153},[129,2785,304],{"class":157},[129,2787,734],{"class":153},[129,2789,362],{"class":139},[129,2791,212],{"class":139},[129,2793,2794,2796,2798,2800,2802,2804],{"class":131,"line":258},[129,2795,206],{"class":180},[129,2797,209],{"class":139},[129,2799,1074],{"class":139},[129,2801,371],{"class":370},[129,2803,1079],{"class":143},[129,2805,186],{"class":139},[129,2807,2808],{"class":131,"line":264},[129,2809,2810],{"class":192},"    \u002F\u002F \"as Produto[]\" diz ao TypeScript que este array só aceita objetos do tipo Produto\n",[129,2812,2813],{"class":131,"line":274},[129,2814,2815],{"class":192},"    \u002F\u002F a partir daqui, toda a store tem inferência de tipos automática\n",[129,2817,2818,2820,2822,2824,2827,2829],{"class":131,"line":292},[129,2819,1586],{"class":205},[129,2821,209],{"class":139},[129,2823,1090],{"class":143},[129,2825,2826],{"class":135},"as",[129,2828,2726],{"class":2725},[129,2830,2831],{"class":143},"[]\n",[129,2833,2834,2836,2838],{"class":131,"line":313},[129,2835,1595],{"class":139},[129,2837,287],{"class":143},[129,2839,227],{"class":139},[129,2841,2842,2844,2846],{"class":131,"line":319},[129,2843,267],{"class":205},[129,2845,209],{"class":139},[129,2847,212],{"class":139},[129,2849,2850],{"class":131,"line":333},[129,2851,2852],{"class":192},"    \u002F\u002F a anotação \": number\" é necessária aqui por conta de uma limitação do TS\n",[129,2854,2855],{"class":131,"line":339},[129,2856,2857],{"class":192},"    \u002F\u002F quando o getter referencia outro getter via \"this\" — neste caso é boa prática anotar\n",[129,2859,2860,2862,2864,2866,2868,2870,2872,2875],{"class":131,"line":397},[129,2861,322],{"class":180},[129,2863,209],{"class":139},[129,2865,1079],{"class":139},[129,2867,284],{"class":283},[129,2869,287],{"class":139},[129,2871,209],{"class":377},[129,2873,2874],{"class":2739}," number",[129,2876,2456],{"class":370},[129,2878,2879,2881,2883,2885,2887,2889,2891,2893,2895,2897,2899,2901,2903,2905,2907,2909,2911,2913,2915,2917],{"class":131,"line":403},[129,2880,463],{"class":143},[129,2882,301],{"class":139},[129,2884,1128],{"class":143},[129,2886,301],{"class":139},[129,2888,352],{"class":180},[129,2890,183],{"class":143},[129,2892,183],{"class":139},[129,2894,359],{"class":283},[129,2896,362],{"class":139},[129,2898,365],{"class":283},[129,2900,287],{"class":139},[129,2902,371],{"class":370},[129,2904,1684],{"class":143},[129,2906,1687],{"class":377},[129,2908,365],{"class":143},[129,2910,301],{"class":139},[129,2912,385],{"class":143},[129,2914,362],{"class":139},[129,2916,391],{"class":390},[129,2918,394],{"class":143},[129,2920,2921],{"class":131,"line":408},[129,2922,244],{"class":139},[129,2924,2925,2927,2929],{"class":131,"line":413},[129,2926,625],{"class":205},[129,2928,209],{"class":139},[129,2930,212],{"class":139},[129,2932,2933],{"class":131,"line":419},[129,2934,2935],{"class":192},"    \u002F\u002F TypeScript já sabe que \"produto\" deve ser do tipo Produto\n",[129,2937,2938],{"class":131,"line":425},[129,2939,2940],{"class":192},"    \u002F\u002F se você tentar passar um objeto sem o campo \"preco\", o editor vai reclamar\n",[129,2942,2943,2945,2947,2949,2951,2953,2955],{"class":131,"line":431},[129,2944,1168],{"class":277},[129,2946,183],{"class":139},[129,2948,517],{"class":283},[129,2950,209],{"class":377},[129,2952,2726],{"class":2725},[129,2954,287],{"class":139},[129,2956,212],{"class":139},[129,2958,2959,2961,2963,2965,2967,2969,2971,2973],{"class":131,"line":441},[129,2960,1747],{"class":223},[129,2962,301],{"class":139},[129,2964,1128],{"class":143},[129,2966,301],{"class":139},[129,2968,512],{"class":180},[129,2970,183],{"class":205},[129,2972,517],{"class":143},[129,2974,394],{"class":205},[129,2976,2977],{"class":131,"line":460},[129,2978,400],{"class":139},[129,2980,2981],{"class":131,"line":477},[129,2982,799],{"class":139},[129,2984,2985,2987],{"class":131,"line":482},[129,2986,805],{"class":139},[129,2988,394],{"class":143},[11,2990,2991,2992,2995,2996,2998,2999,3002,3003,3006,3007,3010,3011,3013],{},"A partir daqui, o TypeScript vai inferir que ",[37,2993,2994],{},"carrinho.itens"," é um array de ",[37,2997,2147],{},", que ",[37,3000,3001],{},"carrinho.totalValor"," é um ",[37,3004,3005],{},"number",", e que ",[37,3008,3009],{},"carrinho.adicionar"," espera um objeto do tipo ",[37,3012,2147],{},". Tudo isso sem configuração extra.",[76,3015,3017],{"id":3016},"modificação-direta-de-estado","Modificação direta de estado",[11,3019,3020],{},"Uma funcionalidade que surpreende quem vem do Vuex é que no Pinia é possível modificar o estado diretamente fora de uma action, quando necessário:",[120,3022,3024],{"className":122,"code":3023,"language":124,"meta":125,"style":125},"const carrinho = useCarrinhoStore()\n\n\u002F\u002F forma 1: modificação direta de uma propriedade do state\n\u002F\u002F funciona, mas não é rastreada como uma única operação no DevTools\ncarrinho.itens = []\n\n\u002F\u002F forma 2: $patch com objeto — ideal para mudanças simples em uma ou mais propriedades\n\u002F\u002F aparece como uma única mutação no Vue DevTools\ncarrinho.$patch({ itens: [] })\n\n\u002F\u002F forma 3: $patch com função — ideal quando a nova mudança depende do estado atual\n\u002F\u002F recebe o state como argumento e você o modifica diretamente\ncarrinho.$patch((state) => {\n  state.itens = state.itens.filter(item => item.ativo)\n})\n",[37,3025,3026,3038,3042,3047,3052,3066,3070,3075,3080,3103,3107,3112,3117,3137,3172],{"__ignoreMap":125},[129,3027,3028,3030,3032,3034,3036],{"class":131,"line":132},[129,3029,1035],{"class":370},[129,3031,2087],{"class":309},[129,3033,471],{"class":377},[129,3035,1541],{"class":180},[129,3037,711],{"class":143},[129,3039,3040],{"class":131,"line":164},[129,3041,168],{"emptyLinePlaceholder":167},[129,3043,3044],{"class":131,"line":171},[129,3045,3046],{"class":192},"\u002F\u002F forma 1: modificação direta de uma propriedade do state\n",[129,3048,3049],{"class":131,"line":189},[129,3050,3051],{"class":192},"\u002F\u002F funciona, mas não é rastreada como uma única operação no DevTools\n",[129,3053,3054,3056,3058,3061,3064],{"class":131,"line":196},[129,3055,304],{"class":143},[129,3057,301],{"class":139},[129,3059,3060],{"class":143},"itens ",[129,3062,3063],{"class":377},"=",[129,3065,238],{"class":143},[129,3067,3068],{"class":131,"line":202},[129,3069,168],{"emptyLinePlaceholder":167},[129,3071,3072],{"class":131,"line":215},[129,3073,3074],{"class":192},"\u002F\u002F forma 2: $patch com objeto — ideal para mudanças simples em uma ou mais propriedades\n",[129,3076,3077],{"class":131,"line":230},[129,3078,3079],{"class":192},"\u002F\u002F aparece como uma única mutação no Vue DevTools\n",[129,3081,3082,3084,3086,3089,3091,3093,3095,3097,3099,3101],{"class":131,"line":241},[129,3083,304],{"class":143},[129,3085,301],{"class":139},[129,3087,3088],{"class":180},"$patch",[129,3090,183],{"class":143},[129,3092,1082],{"class":139},[129,3094,1085],{"class":205},[129,3096,209],{"class":139},[129,3098,1090],{"class":143},[129,3100,805],{"class":139},[129,3102,394],{"class":143},[129,3104,3105],{"class":131,"line":247},[129,3106,168],{"emptyLinePlaceholder":167},[129,3108,3109],{"class":131,"line":252},[129,3110,3111],{"class":192},"\u002F\u002F forma 3: $patch com função — ideal quando a nova mudança depende do estado atual\n",[129,3113,3114],{"class":131,"line":258},[129,3115,3116],{"class":192},"\u002F\u002F recebe o state como argumento e você o modifica diretamente\n",[129,3118,3119,3121,3123,3125,3127,3129,3131,3133,3135],{"class":131,"line":264},[129,3120,304],{"class":143},[129,3122,301],{"class":139},[129,3124,3088],{"class":180},[129,3126,183],{"class":143},[129,3128,183],{"class":139},[129,3130,284],{"class":283},[129,3132,287],{"class":139},[129,3134,371],{"class":370},[129,3136,212],{"class":139},[129,3138,3139,3141,3143,3145,3147,3149,3151,3153,3155,3157,3159,3161,3163,3165,3167,3170],{"class":131,"line":274},[129,3140,206],{"class":143},[129,3142,301],{"class":139},[129,3144,1128],{"class":143},[129,3146,471],{"class":377},[129,3148,298],{"class":143},[129,3150,301],{"class":139},[129,3152,1128],{"class":143},[129,3154,301],{"class":139},[129,3156,565],{"class":180},[129,3158,183],{"class":205},[129,3160,570],{"class":283},[129,3162,371],{"class":370},[129,3164,365],{"class":143},[129,3166,301],{"class":139},[129,3168,3169],{"class":143},"ativo",[129,3171,394],{"class":205},[129,3173,3174,3176],{"class":131,"line":292},[129,3175,805],{"class":139},[129,3177,394],{"class":143},[11,3179,3180,3181,3183],{},"O método ",[37,3182,3088],{}," é especialmente útil para aplicar múltiplas mudanças de forma atômica, sem precisar criar uma action específica para cada pequena atualização. Isso não significa que você deva abandonar as actions, elas continuam sendo o lugar ideal para lógica reutilizável e operações assíncronas, mas você tem a flexibilidade de agir diretamente quando faz sentido.",[76,3185,3187],{"id":3186},"pinia-com-nuxt-3","Pinia com Nuxt 3",[11,3189,3190,3191,3194,3195,3199],{},"Para quem usa Nuxt (como é o caso da stack descrita neste blog), o Pinia é suporte oficial. O módulo ",[37,3192,3193],{},"@pinia\u002Fnuxt"," se integra perfeitamente com SSR, garantindo que o estado não vaze entre requisições de diferentes usuários, um problema real em aplicações server-side rendered. Você pode ver isso funcionando na prática no artigo ",[59,3196,3198],{"href":2668,"rel":3197},[63],"VisitCardGenerator: gerador de cartões de visita em PDF do zero com Nuxt 3",", onde o estado do editor fica inteiramente em uma store Pinia com getters computados, persistência em localStorage e reset de estado.",[120,3201,3203],{"className":2681,"code":3202,"language":2683,"meta":125,"style":125},"export default defineNuxtConfig({\n  \u002F\u002F adicionar o módulo aqui é tudo que você precisa fazer\n  \u002F\u002F o Pinia fica disponível globalmente, com suporte a SSR configurado automaticamente\n  modules: ['@pinia\u002Fnuxt']\n})\n",[37,3204,3205,3218,3223,3228,3246],{"__ignoreMap":125},[129,3206,3207,3209,3211,3214,3216],{"class":131,"line":132},[129,3208,174],{"class":135},[129,3210,177],{"class":135},[129,3212,3213],{"class":180}," defineNuxtConfig",[129,3215,183],{"class":143},[129,3217,186],{"class":139},[129,3219,3220],{"class":131,"line":164},[129,3221,3222],{"class":192},"  \u002F\u002F adicionar o módulo aqui é tudo que você precisa fazer\n",[129,3224,3225],{"class":131,"line":171},[129,3226,3227],{"class":192},"  \u002F\u002F o Pinia fica disponível globalmente, com suporte a SSR configurado automaticamente\n",[129,3229,3230,3232,3234,3237,3239,3241,3243],{"class":131,"line":189},[129,3231,1341],{"class":205},[129,3233,209],{"class":139},[129,3235,3236],{"class":143}," [",[129,3238,734],{"class":153},[129,3240,3193],{"class":157},[129,3242,734],{"class":153},[129,3244,3245],{"class":143},"]\n",[129,3247,3248,3250],{"class":131,"line":196},[129,3249,805],{"class":139},[129,3251,394],{"class":143},[11,3253,3254],{},"Com esse módulo, os stores do Pinia são automaticamente registrados e funcionam corretamente tanto no servidor quanto no cliente, sem nenhuma configuração adicional para hidratação de estado.",[23,3256],{},[26,3258,3260],{"id":3259},"comparação-direta-vuex-vs-pinia","Comparação direta: Vuex vs Pinia",[11,3262,3263],{},"Para deixar as diferenças ainda mais claras, veja uma comparação objetiva dos dois nos principais aspectos:",[76,3265,3267],{"id":3266},"estrutura-conceitual","Estrutura conceitual",[3269,3270,3271,3287],"table",{},[3272,3273,3274],"thead",{},[3275,3276,3277,3281,3284],"tr",{},[3278,3279,3280],"th",{},"Conceito",[3278,3282,3283],{},"Vuex",[3278,3285,3286],{},"Pinia",[3288,3289,3290,3300,3308,3318,3327],"tbody",{},[3275,3291,3292,3295,3298],{},[3293,3294,92],"td",{},[3293,3296,3297],{},"Sim",[3293,3299,3297],{},[3275,3301,3302,3304,3306],{},[3293,3303,98],{},[3293,3305,3297],{},[3293,3307,3297],{},[3275,3309,3310,3312,3315],{},[3293,3311,104],{},[3293,3313,3314],{},"Sim (obrigatório)",[3293,3316,3317],{},"Não existe",[3275,3319,3320,3322,3324],{},[3293,3321,110],{},[3293,3323,3297],{},[3293,3325,3326],{},"Sim (tudo vai aqui)",[3275,3328,3329,3332,3335],{},[3293,3330,3331],{},"Modules",[3293,3333,3334],{},"Sim (nested)",[3293,3336,3337],{},"Múltiplos stores independentes",[76,3339,3341],{"id":3340},"instalação-e-configuração","Instalação e configuração",[11,3343,3344],{},"No Vuex, a instalação é direta, mas a configuração do store exige mais estrutura desde o início:",[120,3346,3348],{"className":122,"code":3347,"language":124,"meta":125,"style":125},"import { createApp } from 'vue'\nimport { createStore } from 'vuex'\nimport App from '.\u002FApp.vue'\n\n\u002F\u002F createStore recebe toda a configuração de uma vez\n\u002F\u002F state, mutations, actions, getters e modules ficam centralizados aqui\nconst store = createStore({ \u002F* ... *\u002F })\nconst app = createApp(App)\napp.use(store) \u002F\u002F registra o store globalmente, acessível via this.$store em qualquer componente\napp.mount('#app')\n",[37,3349,3350,3369,3387,3404,3408,3413,3418,3440,3454,3470],{"__ignoreMap":125},[129,3351,3352,3354,3356,3359,3361,3363,3365,3367],{"class":131,"line":132},[129,3353,136],{"class":135},[129,3355,140],{"class":139},[129,3357,3358],{"class":143}," createApp",[129,3360,147],{"class":139},[129,3362,150],{"class":135},[129,3364,154],{"class":153},[129,3366,2005],{"class":157},[129,3368,161],{"class":153},[129,3370,3371,3373,3375,3377,3379,3381,3383,3385],{"class":131,"line":164},[129,3372,136],{"class":135},[129,3374,140],{"class":139},[129,3376,144],{"class":143},[129,3378,147],{"class":139},[129,3380,150],{"class":135},[129,3382,154],{"class":153},[129,3384,158],{"class":157},[129,3386,161],{"class":153},[129,3388,3389,3391,3394,3397,3399,3402],{"class":131,"line":171},[129,3390,136],{"class":135},[129,3392,3393],{"class":143}," App ",[129,3395,3396],{"class":135},"from",[129,3398,154],{"class":153},[129,3400,3401],{"class":157},".\u002FApp.vue",[129,3403,161],{"class":153},[129,3405,3406],{"class":131,"line":189},[129,3407,168],{"emptyLinePlaceholder":167},[129,3409,3410],{"class":131,"line":196},[129,3411,3412],{"class":192},"\u002F\u002F createStore recebe toda a configuração de uma vez\n",[129,3414,3415],{"class":131,"line":202},[129,3416,3417],{"class":192},"\u002F\u002F state, mutations, actions, getters e modules ficam centralizados aqui\n",[129,3419,3420,3422,3425,3427,3429,3431,3433,3436,3438],{"class":131,"line":215},[129,3421,1035],{"class":370},[129,3423,3424],{"class":309}," store",[129,3426,471],{"class":377},[129,3428,144],{"class":180},[129,3430,183],{"class":143},[129,3432,1082],{"class":139},[129,3434,3435],{"class":192}," \u002F* ... *\u002F",[129,3437,147],{"class":139},[129,3439,394],{"class":143},[129,3441,3442,3444,3447,3449,3451],{"class":131,"line":230},[129,3443,1035],{"class":370},[129,3445,3446],{"class":309}," app",[129,3448,471],{"class":377},[129,3450,3358],{"class":180},[129,3452,3453],{"class":143},"(App)\n",[129,3455,3456,3459,3461,3464,3467],{"class":131,"line":241},[129,3457,3458],{"class":143},"app",[129,3460,301],{"class":139},[129,3462,3463],{"class":180},"use",[129,3465,3466],{"class":143},"(store) ",[129,3468,3469],{"class":192},"\u002F\u002F registra o store globalmente, acessível via this.$store em qualquer componente\n",[129,3471,3472,3474,3476,3479,3481,3483,3486,3488],{"class":131,"line":247},[129,3473,3458],{"class":143},[129,3475,301],{"class":139},[129,3477,3478],{"class":180},"mount",[129,3480,183],{"class":143},[129,3482,734],{"class":153},[129,3484,3485],{"class":157},"#app",[129,3487,734],{"class":153},[129,3489,394],{"class":143},[11,3491,3492],{},"No Pinia, a configuração é igualmente simples e os stores são criados de forma independente conforme a necessidade:",[120,3494,3496],{"className":122,"code":3495,"language":124,"meta":125,"style":125},"import { createApp } from 'vue'\nimport { createPinia } from 'pinia'\nimport App from '.\u002FApp.vue'\n\nconst app = createApp(App)\n\u002F\u002F createPinia() inicializa o sistema de stores\n\u002F\u002F cada store individual é criado e importado separadamente, sob demanda\napp.use(createPinia())\napp.mount('#app')\n",[37,3497,3498,3516,3535,3549,3553,3565,3570,3575,3591],{"__ignoreMap":125},[129,3499,3500,3502,3504,3506,3508,3510,3512,3514],{"class":131,"line":132},[129,3501,136],{"class":135},[129,3503,140],{"class":139},[129,3505,3358],{"class":143},[129,3507,147],{"class":139},[129,3509,150],{"class":135},[129,3511,154],{"class":153},[129,3513,2005],{"class":157},[129,3515,161],{"class":153},[129,3517,3518,3520,3522,3525,3527,3529,3531,3533],{"class":131,"line":164},[129,3519,136],{"class":135},[129,3521,140],{"class":139},[129,3523,3524],{"class":143}," createPinia",[129,3526,147],{"class":139},[129,3528,150],{"class":135},[129,3530,154],{"class":153},[129,3532,1505],{"class":157},[129,3534,161],{"class":153},[129,3536,3537,3539,3541,3543,3545,3547],{"class":131,"line":171},[129,3538,136],{"class":135},[129,3540,3393],{"class":143},[129,3542,3396],{"class":135},[129,3544,154],{"class":153},[129,3546,3401],{"class":157},[129,3548,161],{"class":153},[129,3550,3551],{"class":131,"line":189},[129,3552,168],{"emptyLinePlaceholder":167},[129,3554,3555,3557,3559,3561,3563],{"class":131,"line":196},[129,3556,1035],{"class":370},[129,3558,3446],{"class":309},[129,3560,471],{"class":377},[129,3562,3358],{"class":180},[129,3564,3453],{"class":143},[129,3566,3567],{"class":131,"line":202},[129,3568,3569],{"class":192},"\u002F\u002F createPinia() inicializa o sistema de stores\n",[129,3571,3572],{"class":131,"line":215},[129,3573,3574],{"class":192},"\u002F\u002F cada store individual é criado e importado separadamente, sob demanda\n",[129,3576,3577,3579,3581,3583,3585,3588],{"class":131,"line":230},[129,3578,3458],{"class":143},[129,3580,301],{"class":139},[129,3582,3463],{"class":180},[129,3584,183],{"class":143},[129,3586,3587],{"class":180},"createPinia",[129,3589,3590],{"class":143},"())\n",[129,3592,3593,3595,3597,3599,3601,3603,3605,3607],{"class":131,"line":241},[129,3594,3458],{"class":143},[129,3596,301],{"class":139},[129,3598,3478],{"class":180},[129,3600,183],{"class":143},[129,3602,734],{"class":153},[129,3604,3485],{"class":157},[129,3606,734],{"class":153},[129,3608,394],{"class":143},[76,3610,3612],{"id":3611},"como-os-stores-se-comunicam","Como os stores se comunicam",[11,3614,3615,3616,1022,3619,3622],{},"No Vuex, a comunicação entre módulos pode ser feita via ",[37,3617,3618],{},"rootState",[37,3620,3621],{},"rootGetters",", o que tende a criar acoplamentos não muito explícitos:",[120,3624,3626],{"className":122,"code":3625,"language":124,"meta":125,"style":125},"const moduloA = {\n  actions: {\n    \u002F\u002F para acessar o estado de outro módulo no Vuex,\n    \u002F\u002F você precisa do rootState que é injetado pelo próprio Vuex no contexto da action\n    \u002F\u002F isso funciona, mas o acoplamento é implícito: você não sabe de onde vem rootState\n    fazAlgo({ commit, rootState }) {\n      if (rootState.usuario.autenticado) {\n        commit('ATUALIZAR')\n      }\n    }\n  }\n}\n",[37,3627,3628,3639,3647,3652,3657,3662,3681,3703,3719,3724,3728,3732],{"__ignoreMap":125},[129,3629,3630,3632,3635,3637],{"class":131,"line":132},[129,3631,1035],{"class":370},[129,3633,3634],{"class":309}," moduloA",[129,3636,471],{"class":377},[129,3638,212],{"class":139},[129,3640,3641,3643,3645],{"class":131,"line":164},[129,3642,625],{"class":205},[129,3644,209],{"class":139},[129,3646,212],{"class":139},[129,3648,3649],{"class":131,"line":171},[129,3650,3651],{"class":192},"    \u002F\u002F para acessar o estado de outro módulo no Vuex,\n",[129,3653,3654],{"class":131,"line":189},[129,3655,3656],{"class":192},"    \u002F\u002F você precisa do rootState que é injetado pelo próprio Vuex no contexto da action\n",[129,3658,3659],{"class":131,"line":196},[129,3660,3661],{"class":192},"    \u002F\u002F isso funciona, mas o acoplamento é implícito: você não sabe de onde vem rootState\n",[129,3663,3664,3667,3669,3671,3673,3676,3679],{"class":131,"line":202},[129,3665,3666],{"class":277},"    fazAlgo",[129,3668,641],{"class":139},[129,3670,644],{"class":283},[129,3672,362],{"class":139},[129,3674,3675],{"class":283}," rootState",[129,3677,3678],{"class":139}," })",[129,3680,212],{"class":139},[129,3682,3683,3686,3688,3690,3692,3694,3696,3699,3701],{"class":131,"line":215},[129,3684,3685],{"class":135},"      if",[129,3687,1079],{"class":205},[129,3689,3618],{"class":143},[129,3691,301],{"class":139},[129,3693,468],{"class":143},[129,3695,301],{"class":139},[129,3697,3698],{"class":143},"autenticado",[129,3700,1139],{"class":205},[129,3702,186],{"class":139},[129,3704,3705,3708,3710,3712,3715,3717],{"class":131,"line":230},[129,3706,3707],{"class":180},"        commit",[129,3709,183],{"class":205},[129,3711,734],{"class":153},[129,3713,3714],{"class":157},"ATUALIZAR",[129,3716,734],{"class":153},[129,3718,394],{"class":205},[129,3720,3721],{"class":131,"line":241},[129,3722,3723],{"class":139},"      }\n",[129,3725,3726],{"class":131,"line":247},[129,3727,400],{"class":139},[129,3729,3730],{"class":131,"line":252},[129,3731,799],{"class":139},[129,3733,3734],{"class":131,"line":258},[129,3735,1001],{"class":139},[11,3737,3738],{},"No Pinia, você simplesmente importa e usa outro store dentro de um store, de forma completamente explícita:",[120,3740,3742],{"className":122,"code":3741,"language":124,"meta":125,"style":125},"import { useUsuarioStore } from '.\u002Fusuario'\n\nexport const useCarrinhoStore = defineStore('carrinho', {\n  actions: {\n    adicionar(produto) {\n      \u002F\u002F importar e usar outro store é simples e explícito\n      \u002F\u002F o acoplamento fica visível logo no import, sem mágica\n      const usuario = useUsuarioStore()\n      if (!usuario.autenticado) {\n        throw new Error('Usuário precisa estar logado')\n      }\n      this.itens.push(produto)\n    }\n  }\n})\n",[37,3743,3744,3763,3767,3791,3799,3811,3816,3821,3833,3852,3874,3878,3896,3900,3904],{"__ignoreMap":125},[129,3745,3746,3748,3750,3752,3754,3756,3758,3761],{"class":131,"line":132},[129,3747,136],{"class":135},[129,3749,140],{"class":139},[129,3751,1858],{"class":143},[129,3753,147],{"class":139},[129,3755,150],{"class":135},[129,3757,154],{"class":153},[129,3759,3760],{"class":157},".\u002Fusuario",[129,3762,161],{"class":153},[129,3764,3765],{"class":131,"line":164},[129,3766,168],{"emptyLinePlaceholder":167},[129,3768,3769,3771,3773,3775,3777,3779,3781,3783,3785,3787,3789],{"class":131,"line":171},[129,3770,174],{"class":135},[129,3772,1538],{"class":370},[129,3774,1541],{"class":309},[129,3776,471],{"class":377},[129,3778,1496],{"class":180},[129,3780,183],{"class":143},[129,3782,734],{"class":153},[129,3784,304],{"class":157},[129,3786,734],{"class":153},[129,3788,362],{"class":139},[129,3790,212],{"class":139},[129,3792,3793,3795,3797],{"class":131,"line":189},[129,3794,625],{"class":205},[129,3796,209],{"class":139},[129,3798,212],{"class":139},[129,3800,3801,3803,3805,3807,3809],{"class":131,"line":196},[129,3802,1168],{"class":277},[129,3804,183],{"class":139},[129,3806,517],{"class":283},[129,3808,287],{"class":139},[129,3810,212],{"class":139},[129,3812,3813],{"class":131,"line":202},[129,3814,3815],{"class":192},"      \u002F\u002F importar e usar outro store é simples e explícito\n",[129,3817,3818],{"class":131,"line":215},[129,3819,3820],{"class":192},"      \u002F\u002F o acoplamento fica visível logo no import, sem mágica\n",[129,3822,3823,3825,3827,3829,3831],{"class":131,"line":230},[129,3824,660],{"class":370},[129,3826,453],{"class":309},[129,3828,471],{"class":377},[129,3830,1858],{"class":180},[129,3832,711],{"class":205},[129,3834,3835,3837,3839,3842,3844,3846,3848,3850],{"class":131,"line":241},[129,3836,3685],{"class":135},[129,3838,1079],{"class":205},[129,3840,3841],{"class":377},"!",[129,3843,468],{"class":143},[129,3845,301],{"class":139},[129,3847,3698],{"class":143},[129,3849,1139],{"class":205},[129,3851,186],{"class":139},[129,3853,3854,3857,3860,3863,3865,3867,3870,3872],{"class":131,"line":247},[129,3855,3856],{"class":135},"        throw",[129,3858,3859],{"class":377}," new",[129,3861,3862],{"class":180}," Error",[129,3864,183],{"class":205},[129,3866,734],{"class":153},[129,3868,3869],{"class":157},"Usuário precisa estar logado",[129,3871,734],{"class":153},[129,3873,394],{"class":205},[129,3875,3876],{"class":131,"line":252},[129,3877,3723],{"class":139},[129,3879,3880,3882,3884,3886,3888,3890,3892,3894],{"class":131,"line":258},[129,3881,1747],{"class":223},[129,3883,301],{"class":139},[129,3885,1128],{"class":143},[129,3887,301],{"class":139},[129,3889,512],{"class":180},[129,3891,183],{"class":205},[129,3893,517],{"class":143},[129,3895,394],{"class":205},[129,3897,3898],{"class":131,"line":264},[129,3899,400],{"class":139},[129,3901,3902],{"class":131,"line":274},[129,3903,799],{"class":139},[129,3905,3906,3908],{"class":131,"line":292},[129,3907,805],{"class":139},[129,3909,394],{"class":143},[76,3911,3913],{"id":3912},"tamanho-do-bundle","Tamanho do bundle",[11,3915,3916,3917,3920,3921,3924],{},"O Pinia pesa aproximadamente ",[84,3918,3919],{},"1.5kb"," gzipado. O Vuex 4 fica em torno de ",[84,3922,3923],{},"6.5kb",". Para a maioria das aplicações isso não faz diferença prática, mas em projetos onde performance de carregamento é crítica, esse detalhe importa.",[23,3926],{},[26,3928,3930],{"id":3929},"dúvidas-frequentes-respondidas","Dúvidas frequentes respondidas",[76,3932,3934],{"id":3933},"preciso-migrar-meu-projeto-vuex-para-pinia-agora","\"Preciso migrar meu projeto Vuex para Pinia agora?\"",[11,3936,3937],{},"Não. Se você tem um projeto Vue 2 ou Vue 3 com Vuex funcionando bem, não há urgência. O Vuex 3 e 4 continuam sendo mantidos. A migração faz sentido quando você está iniciando um novo projeto, quando a dívida técnica do Vuex está atrapalhando a evolução do código, ou quando a equipe quer aproveitar melhor TypeScript e Composition API.",[76,3939,3941],{"id":3940},"dá-para-usar-pinia-com-vue-2","\"Dá para usar Pinia com Vue 2?\"",[11,3943,3944],{},"Sim, mas com limitações. O suporte a Vue 2 no Pinia foi descontinuado em 2025. Para projetos Vue 2 ativos, o Vuex 3 continua sendo a escolha mais adequada.",[76,3946,3948],{"id":3947},"pinia-é-mais-performático-que-vuex","\"Pinia é mais performático que Vuex?\"",[11,3950,3951],{},"Em termos de execução em tempo real, as diferenças são mínimas na maioria dos cenários. O ganho real do Pinia em performance vem da arquitetura modular, que permite ao bundler fazer tree-shaking mais eficiente, carregando apenas os stores que a aplicação realmente usa.",[76,3953,3955],{"id":3954},"posso-usar-vuex-e-pinia-no-mesmo-projeto","\"Posso usar Vuex e Pinia no mesmo projeto?\"",[11,3957,3958],{},"Tecnicamente sim. Durante uma migração gradual de Vuex para Pinia em um projeto grande, é possível ter os dois instalados e ir substituindo módulo por módulo. Mas manter os dois permanentemente não é uma prática recomendada.",[76,3960,3962],{"id":3961},"as-devtools-funcionam-igual-nos-dois","\"As DevTools funcionam igual nos dois?\"",[11,3964,3965,3966,3968],{},"Ambos têm integração com o Vue DevTools, mas a experiência é diferente. No Pinia, cada store aparece de forma independente na aba de estado, você consegue visualizar mutations (que no Pinia são as modificações diretas via actions ou ",[37,3967,3088],{},"), fazer time-travel debugging e inspecionar getters. O Pinia também traz melhorias na visibilidade de quais componentes estão consumindo cada store.",[23,3970],{},[26,3972,3974],{"id":3973},"quando-usar-cada-um","Quando usar cada um",[11,3976,3977],{},[84,3978,3979],{},"Use Vuex quando:",[11,3981,3982],{},"Você está mantendo um projeto Vue 2 que não tem planos de migração para Vue 3 no curto prazo. Ou quando você tem uma aplicação Vue 3 com uma arquitetura Vuex muito bem estabelecida e migrar não traria ganhos proporcionais ao esforço.",[11,3984,3985],{},[84,3986,3987],{},"Use Pinia quando:",[11,3989,3990],{},"Você está iniciando qualquer projeto Vue 3 novo. Quando a aplicação usa Nuxt 3. Quando TypeScript é importante para o projeto. Quando a equipe inclui desenvolvedores em diferentes níveis de experiência e você quer um modelo mental mais simples. Em resumo: para tudo que é novo com Vue 3, Pinia é a escolha natural e recomendada.",[23,3992],{},[26,3994,3996],{"id":3995},"migrando-de-vuex-para-pinia","Migrando de Vuex para Pinia",[11,3998,3999,4000,4005],{},"Se você decidiu migrar, o processo é mais tranquilo do que parece. A documentação oficial do Pinia tem um ",[59,4001,4004],{"href":4002,"rel":4003},"https:\u002F\u002Fpinia.vuejs.org\u002Fcookbook\u002Fmigration-vuex.html",[63],"guia de migração"," dedicado. A lógica geral é:",[11,4007,4008,4009,4011,4012,4015,4016,4019],{},"Cada módulo Vuex com ",[37,4010,1380],{}," vira um store Pinia independente. As mutations deixam de existir e sua lógica é absorvida pelas actions. Os getters permanecem praticamente iguais. As actions assíncronas ficam quase idênticas, apenas removendo o parâmetro de context (",[37,4013,4014],{},"{ commit, state }",") e usando ",[37,4017,4018],{},"this"," diretamente.",[120,4021,4023],{"className":122,"code":4022,"language":124,"meta":125,"style":125},"\u002F\u002F ------ ANTES: módulo Vuex ------\nconst moduloVuex = {\n  namespaced: true,\n  state: () => ({ lista: [] }),\n  \u002F\u002F mutation obrigatória só para atualizar o state\n  mutations: {\n    SET_LISTA(state, lista) { state.lista = lista }\n  },\n  \u002F\u002F action que chama a API e depois precisa \"comitar\" a mutation\n  actions: {\n    async buscarLista({ commit }) {\n      const data = await api.getLista()\n      commit('SET_LISTA', data) \u002F\u002F duas etapas para uma operação simples\n    }\n  }\n}\n\n\u002F\u002F ------ DEPOIS: store Pinia equivalente ------\nexport const useListaStore = defineStore('lista', {\n  state: () => ({ lista: [] }),\n  \u002F\u002F sem mutation, a action faz tudo diretamente\n  actions: {\n    async buscarLista() {\n      this.lista = await api.getLista() \u002F\u002F uma única linha\n    }\n  }\n})\n",[37,4024,4025,4030,4041,4051,4078,4083,4091,4121,4125,4130,4138,4153,4174,4196,4200,4204,4208,4212,4217,4242,4268,4273,4281,4291,4315,4319,4323],{"__ignoreMap":125},[129,4026,4027],{"class":131,"line":132},[129,4028,4029],{"class":192},"\u002F\u002F ------ ANTES: módulo Vuex ------\n",[129,4031,4032,4034,4037,4039],{"class":131,"line":164},[129,4033,1035],{"class":370},[129,4035,4036],{"class":309}," moduloVuex",[129,4038,471],{"class":377},[129,4040,212],{"class":139},[129,4042,4043,4045,4047,4049],{"class":131,"line":171},[129,4044,1057],{"class":205},[129,4046,209],{"class":139},[129,4048,1063],{"class":1062},[129,4050,227],{"class":139},[129,4052,4053,4055,4057,4059,4061,4063,4065,4068,4070,4072,4074,4076],{"class":131,"line":189},[129,4054,206],{"class":180},[129,4056,209],{"class":139},[129,4058,1074],{"class":139},[129,4060,371],{"class":370},[129,4062,1079],{"class":143},[129,4064,1082],{"class":139},[129,4066,4067],{"class":205}," lista",[129,4069,209],{"class":139},[129,4071,1090],{"class":143},[129,4073,805],{"class":139},[129,4075,287],{"class":143},[129,4077,227],{"class":139},[129,4079,4080],{"class":131,"line":196},[129,4081,4082],{"class":192},"  \u002F\u002F mutation obrigatória só para atualizar o state\n",[129,4084,4085,4087,4089],{"class":131,"line":202},[129,4086,434],{"class":205},[129,4088,209],{"class":139},[129,4090,212],{"class":139},[129,4092,4093,4096,4098,4100,4102,4104,4106,4108,4110,4112,4115,4117,4119],{"class":131,"line":215},[129,4094,4095],{"class":277},"    SET_LISTA",[129,4097,183],{"class":139},[129,4099,284],{"class":283},[129,4101,362],{"class":139},[129,4103,4067],{"class":283},[129,4105,287],{"class":139},[129,4107,140],{"class":139},[129,4109,298],{"class":143},[129,4111,301],{"class":139},[129,4113,4114],{"class":143},"lista",[129,4116,471],{"class":377},[129,4118,4067],{"class":143},[129,4120,1312],{"class":139},[129,4122,4123],{"class":131,"line":230},[129,4124,244],{"class":139},[129,4126,4127],{"class":131,"line":241},[129,4128,4129],{"class":192},"  \u002F\u002F action que chama a API e depois precisa \"comitar\" a mutation\n",[129,4131,4132,4134,4136],{"class":131,"line":247},[129,4133,625],{"class":205},[129,4135,209],{"class":139},[129,4137,212],{"class":139},[129,4139,4140,4142,4145,4147,4149,4151],{"class":131,"line":252},[129,4141,635],{"class":370},[129,4143,4144],{"class":277}," buscarLista",[129,4146,641],{"class":139},[129,4148,644],{"class":283},[129,4150,3678],{"class":139},[129,4152,212],{"class":139},[129,4154,4155,4157,4160,4162,4164,4167,4169,4172],{"class":131,"line":258},[129,4156,660],{"class":370},[129,4158,4159],{"class":309}," data",[129,4161,471],{"class":377},[129,4163,668],{"class":135},[129,4165,4166],{"class":143}," api",[129,4168,301],{"class":139},[129,4170,4171],{"class":180},"getLista",[129,4173,711],{"class":205},[129,4175,4176,4178,4180,4182,4185,4187,4189,4191,4193],{"class":131,"line":264},[129,4177,729],{"class":180},[129,4179,183],{"class":205},[129,4181,734],{"class":153},[129,4183,4184],{"class":157},"SET_LISTA",[129,4186,734],{"class":153},[129,4188,362],{"class":139},[129,4190,4159],{"class":143},[129,4192,1139],{"class":205},[129,4194,4195],{"class":192},"\u002F\u002F duas etapas para uma operação simples\n",[129,4197,4198],{"class":131,"line":274},[129,4199,400],{"class":139},[129,4201,4202],{"class":131,"line":292},[129,4203,799],{"class":139},[129,4205,4206],{"class":131,"line":313},[129,4207,1001],{"class":139},[129,4209,4210],{"class":131,"line":319},[129,4211,168],{"emptyLinePlaceholder":167},[129,4213,4214],{"class":131,"line":333},[129,4215,4216],{"class":192},"\u002F\u002F ------ DEPOIS: store Pinia equivalente ------\n",[129,4218,4219,4221,4223,4226,4228,4230,4232,4234,4236,4238,4240],{"class":131,"line":339},[129,4220,174],{"class":135},[129,4222,1538],{"class":370},[129,4224,4225],{"class":309}," useListaStore",[129,4227,471],{"class":377},[129,4229,1496],{"class":180},[129,4231,183],{"class":143},[129,4233,734],{"class":153},[129,4235,4114],{"class":157},[129,4237,734],{"class":153},[129,4239,362],{"class":139},[129,4241,212],{"class":139},[129,4243,4244,4246,4248,4250,4252,4254,4256,4258,4260,4262,4264,4266],{"class":131,"line":397},[129,4245,206],{"class":180},[129,4247,209],{"class":139},[129,4249,1074],{"class":139},[129,4251,371],{"class":370},[129,4253,1079],{"class":143},[129,4255,1082],{"class":139},[129,4257,4067],{"class":205},[129,4259,209],{"class":139},[129,4261,1090],{"class":143},[129,4263,805],{"class":139},[129,4265,287],{"class":143},[129,4267,227],{"class":139},[129,4269,4270],{"class":131,"line":403},[129,4271,4272],{"class":192},"  \u002F\u002F sem mutation, a action faz tudo diretamente\n",[129,4274,4275,4277,4279],{"class":131,"line":408},[129,4276,625],{"class":205},[129,4278,209],{"class":139},[129,4280,212],{"class":139},[129,4282,4283,4285,4287,4289],{"class":131,"line":413},[129,4284,635],{"class":370},[129,4286,4144],{"class":277},[129,4288,2423],{"class":139},[129,4290,212],{"class":139},[129,4292,4293,4295,4297,4299,4301,4303,4305,4307,4309,4312],{"class":131,"line":419},[129,4294,1747],{"class":223},[129,4296,301],{"class":139},[129,4298,4114],{"class":143},[129,4300,471],{"class":377},[129,4302,668],{"class":135},[129,4304,4166],{"class":143},[129,4306,301],{"class":139},[129,4308,4171],{"class":180},[129,4310,4311],{"class":205},"() ",[129,4313,4314],{"class":192},"\u002F\u002F uma única linha\n",[129,4316,4317],{"class":131,"line":425},[129,4318,400],{"class":139},[129,4320,4321],{"class":131,"line":431},[129,4322,799],{"class":139},[129,4324,4325,4327],{"class":131,"line":441},[129,4326,805],{"class":139},[129,4328,394],{"class":143},[11,4330,4331],{},"A diferença em termos de linhas de código já é visível em um exemplo simples. Em stores mais complexos, o ganho é ainda maior.",[23,4333],{},[26,4335,4337],{"id":4336},"conclusão","Conclusão",[11,4339,4340],{},"O Vuex foi uma solução sólida que moldou como desenvolvedores Vue pensam sobre estado global por anos. Ele ainda é relevante para projetos legados e situações específicas, mas carrega o peso de uma época em que Composition API e TypeScript não eram prioridades centrais do ecossistema.",[11,4342,4343],{},"O Pinia é o que o Vuex teria sido se tivesse sido projetado hoje. Mais simples, mais leve, mais alinhado com a forma moderna de escrever Vue, e com suporte a TypeScript que realmente funciona sem dor. Não é à toa que o time do Vue o elegeu como a solução oficial.",[11,4345,4346,4347,4350],{},"Para qualquer projeto novo com Vue 3, a resposta é direta: use Pinia. O aprendizado é rápido, a API é intuitiva e você vai escrever código mais limpo desde o primeiro dia. E se quiser ver como tudo isso se aplica em um projeto real, o artigo do ",[59,4348,2670],{"href":2668,"rel":4349},[63]," mostra cada decisão técnica documentada, do setup da store à geração do PDF.",[26,4352,4354],{"id":4353},"referências","Referências",[4356,4357,4358,4366,4373],"ul",{},[4359,4360,4361],"li",{},[59,4362,4365],{"href":4363,"rel":4364},"https:\u002F\u002Fvuex.vuejs.org",[63],"Documentação oficial do Vuex",[4359,4367,4368],{},[59,4369,4372],{"href":4370,"rel":4371},"https:\u002F\u002Fpinia.vuejs.org",[63],"Documentação oficial do Pinia",[4359,4374,4375],{},[59,4376,4378],{"href":4002,"rel":4377},[63],"Guia de migração: Vuex para Pinia",[26,4380,4382],{"id":4381},"artigos-complementares","Artigos complementares",[4356,4384,4385,4391],{},[4359,4386,4387],{},[59,4388,4390],{"href":61,"rel":4389},[63],"Closures no JavaScript: o conceito por trás de uma store",[4359,4392,4393],{},[59,4394,4396],{"href":2668,"rel":4395},[63],"VisitCardGenerator: construindo um gerador de cartões de visita em PDF do zero com Nuxt 3 e Pinia",[4398,4399,4400],"style",{},"html pre.shiki code .s3Er8, html code.shiki .s3Er8{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#F97583;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .sG-J9, html code.shiki .sG-J9{--shiki-light:#39ADB5;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sMo7A, html code.shiki .sMo7A{--shiki-light:#90A4AE;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sF_wb, html code.shiki .sF_wb{--shiki-light:#39ADB5;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .s0vBq, html code.shiki .s0vBq{--shiki-light:#91B859;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .sK_r7, html code.shiki .sK_r7{--shiki-light:#6182B8;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .sdv8B, html code.shiki .sdv8B{--shiki-light:#E53935;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .swu5b, html code.shiki .swu5b{--shiki-light:#39ADB5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .s0u7J, html code.shiki .s0u7J{--shiki-light:#E53935;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sk1zL, html code.shiki .sk1zL{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#FFAB70;--shiki-default-font-style:inherit;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit}html pre.shiki code .sVPC0, html code.shiki .sVPC0{--shiki-light:#90A4AE;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .sFsEu, html code.shiki .sFsEu{--shiki-light:#9C3EDA;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .sFfmW, html code.shiki .sFfmW{--shiki-light:#39ADB5;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .s_k96, html code.shiki .s_k96{--shiki-light:#F76D47;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sMrrN, html code.shiki .sMrrN{--shiki-light:#FF5370;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .sqIbZ, html code.shiki .sqIbZ{--shiki-light:#E53935;--shiki-default:#85E89D;--shiki-dark:#85E89D}html pre.shiki code .s7047, html code.shiki .s7047{--shiki-light:#9C3EDA;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .soiBB, html code.shiki .soiBB{--shiki-light:#E2931D;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sTbKH, html code.shiki .sTbKH{--shiki-light:#E53935;--shiki-default:#FFAB70;--shiki-dark:#FFAB70}html pre.shiki code .s3afY, html code.shiki .s3afY{--shiki-light:#E2931D;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}",{"title":125,"searchDepth":164,"depth":164,"links":4402},[4403,4404,4410,4417,4423,4430,4431,4432,4433,4434],{"id":28,"depth":164,"text":29},{"id":70,"depth":164,"text":71,"children":4405},[4406,4407,4408,4409],{"id":78,"depth":171,"text":79},{"id":1004,"depth":171,"text":1005},{"id":1391,"depth":171,"text":1392},{"id":1401,"depth":171,"text":1402},{"id":1439,"depth":164,"text":1440,"children":4411},[4412,4413,4414,4415,4416],{"id":1453,"depth":171,"text":1454},{"id":2266,"depth":171,"text":2267},{"id":2674,"depth":171,"text":2675},{"id":3016,"depth":171,"text":3017},{"id":3186,"depth":171,"text":3187},{"id":3259,"depth":164,"text":3260,"children":4418},[4419,4420,4421,4422],{"id":3266,"depth":171,"text":3267},{"id":3340,"depth":171,"text":3341},{"id":3611,"depth":171,"text":3612},{"id":3912,"depth":171,"text":3913},{"id":3929,"depth":164,"text":3930,"children":4424},[4425,4426,4427,4428,4429],{"id":3933,"depth":171,"text":3934},{"id":3940,"depth":171,"text":3941},{"id":3947,"depth":171,"text":3948},{"id":3954,"depth":171,"text":3955},{"id":3961,"depth":171,"text":3962},{"id":3973,"depth":164,"text":3974},{"id":3995,"depth":164,"text":3996},{"id":4336,"depth":164,"text":4337},{"id":4353,"depth":164,"text":4354},{"id":4381,"depth":164,"text":4382},"2026-04-23T19:31:00-03:00","Entenda as diferenças entre Vuex e Pinia com exemplos práticos, comparação de arquitetura, TypeScript, performance e quando usar cada biblioteca no Vue 3.","md","\u002Fimages\u002Fblog\u002Fvuex-vs-pinia.png",{},"\u002Fblog\u002Fvuex-vs-pinia",{"title":5,"description":4436},"blog\u002Fvuex-vs-pinia",[4444,4445,4446,4447,3283,3286,4448],"Vue","Vue3","JavaScript","Frontend","Gerenciamento de Estado","n0zgHzeRqsVpdXqWmY2xk0k5WMF4uVExvjmYICxkE_Q",1777034220829]