Pinia and Nuxt 3
Tags: nuxt3, nuxt, pinia, vue
Published: 2023-01-03 15:39:00

---
title: Pinia and Nuxt 3

published: true
description: How to get started with Pinia in Nuxt 3
tags: nuxt3, nuxt, pinia, vue
published_at: 2023-01-03 15:39 +0000
---


### Pinia is now the recommended choice by Vue and is now an official part of the whole Vue ecosystem, maintained and developed by core members of the Vue team 
&nbsp;
### Creating a new project
&nbsp;

``` bash
npx nuxi init nuxt3-pinia
```

Install pinia

```bash
npm i @pinia/nuxt pinia -D
```

add module to `nuxt.config.ts`

```js
export default defineNuxtConfig({
  modules: [
    // ...
    '@pinia/nuxt',
  ],
});
```


### Creating a todo store


create `store` folder in root of project, then create a `todos.ts` file, we will be calling  `https://jsonplaceholder.typicode.com/todos` this is a mock API which returns a list of todos 


Before diving into core concepts, we need to know that a store is defined using defineStore() and that it requires a unique name, passed as the first argument:


`store/todos.ts`
```js
import { defineStore } from 'pinia';
export const useTodosStore = defineStore('todos', {

});
```
 In Pinia the state is defined as a function that returns the initial state. This allows Pinia to work in both Server and Client Side.
 
let's create an empty todos state

`store/todos.ts`
```js
  state: () => ({
    todos: [],
  }),
```
Now lets create an action, which will call the endpoint above to fetch a list of todos and assign the data to the todos state

Actions are the equivalent of methods in components. They can be defined with the actions property in defineStore() and they are perfect to define business logic:

`store/todos.ts`

```js
  async fetchTodos() {
      const { data } = await useFetch('https://jsonplaceholder.typicode.com/todos'); 
      if (data.value) {
        this.todos = data.value;
      }
  }
```
Nuxt 3 provides new composable called [useFetch](https://nuxt.com/docs/getting-started/data-fetching#usefetch) this will let us do a GET call without having to install axios 


the completed code now for `store/todos.ts`

```js
import { defineStore } from 'pinia';

export const useTodosStore = defineStore('todos', {
  state: () => ({
    todos: [],
  }),
  actions: {
    async fetchTodos() {
      const { data }: any = await useFetch('https://jsonplaceholder.typicode.com/todos');
      if (data.value) {
        this.todos = data.value;
      }
    },
  },
});
```

### How to use the todos store

open `app.vue` we now need to import our `fetchTodos` function from the `store`

```js
import { useTodosStore } from '~/store/todos';
```

now we need to destructure our store and call the actions, states we need, **destructuring the store will break reactivity.**


```js
const { fetchTodos, todos } = useTodosStore();
```

to maintain the reactivity we can use a `computed` property or `storeToRefs()`

#### Reactivity with computed

use computed property to make todos state reactive 

```js
const store = useTodosStore();

const todos =  computed(() => store.todos)
```

#### Reactivity with storeToRefs()

`storeToRefs()` lets us destructure the store value while keeping it reactive 

```js
import { storeToRefs } from 'pinia'

const store = useTodosStore();
const { todos,} = storeToRefs(store)

```
#### what about functions

`storeToRefs` doesn't allow us to destructure a function we can simply call an action with `store.fetchTodos` or we can destructrutre the store value 

```js
import { storeToRefs } from 'pinia'

const store = useTodosStore();
const { fetchTodos } = store; // have all non reactiave stuff here 
const { todos } = storeToRefs(store) // have all reactive states here
```

because Nuxt 3 supports top level async/await we can just call `fetchTodos` action

```js
await fetchTodos();
```

now on our html can we loop over the todos and display each one 

```html
<template>
  <div>
    <h1>Todos:</h1>
    <ul v-for="todo in todos" :key="todo.id">
      <li>{{ todo.title }}</li>
    </ul>
  </div>
</template>
```
now we should see a list of todos

![](https://sli1n332.directus.app/assets/7ff7dd28-02f7-429c-8ddd-292e0a90390c)

complete code for `app.vue`

```html
<template>
  <div>
    <h1>Todos:</h1>
    <ul v-for="todo in todos" :key="todo.id">
      <li>{{ todo.title }}</li>
    </ul>
  </div>
</template>
<script lang="ts" setup>
import { storeToRefs } from 'pinia';
import { useTodosStore } from '~/store/todos';

const store = useTodosStore();
const { fetchTodos } = store; // have all non reactiave stuff here
const { todos } = storeToRefs(store); // have all reactive states here

await fetchTodos();
</script>
```

### Alternative away of setting up pinia store
<br/>

```js

import { defineStore } from 'pinia';

export const useTodosStore = defineStore('todos', () => {
  const todos = ref([]);  // ref by defaults are states,

 // functions get added to actions
 
  const fetchTodos = async () => { 
    const { data }: any = await useFetch('https://jsonplaceholder.typicode.com/todos');
    if (data.value) {
      todos.value = data.value;
    }
  };

// we must return what we want to use accross the application
  return {
    todos,
    fetchTodos,
  };
});

```

This way of setting up the store feels very familiar way of creating a composbale in vue 


You can find the repository [here](https://github.com/rafaelmagalhaes/nuxt3-pinia)