0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Vue 3】ポートフォリオをスッキリ整理。Pinia (Setup Store) 導入メモと実践手順

Last updated at Posted at 2026-01-04

はじめに

この記事では、Vue 3 の状態管理のデファクトスタンダードである Pinia を導入します。 コンポーネントに直書きしていたデータを分離し、ポートフォリオのコードをスッキリ整理するために、より Vue 3 らしい Setup Store 形式で実装した手順をメモとしてまとめます。

現在、本業のプロジェクトではVue.jsをメインで使用していますが、個人開発ではReactを中心に技術習得をしています。

ポートフォリオ作成をするにあたり、Vue.jsで構築しようと思った理由は以下の2つです。

  1. 実務スキルの深掘り:本業で使用しているVue.jsのエコシステムを体系的に学び直し、現場での実務スピードと品質を向上させたいため
  2. 技術の相対比:ReactとVueの設計思想の違い(Hooks vs Composablesなど)を実際に使って試すことで、状況に応じた最適な技術選定ができるエンジニアを目指すため

1. Piniaのインストール

まずはプロジェクトにPiniaを追加します。

npm install pinia

2. アプリへの登録(main.ts)

Vueアプリのインスタンスに対してPiniaを登録します。

import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'

const app = createApp(App)
const pinia = createPinia()

app.use(pinia)
app.mount('#app')

3. ストアの作成(Setup Store形式)

Piniaには「Option Store」と「Setup Store」の2通りの書き方がありますが、
今回はComposition APIと同じ感覚で書けるSetup Storeを採用しました。

ストアファイルは、一般的に src/stores/ フォルダ内に作成します。
今回はプロフィール情報を管理する想定で profile.ts という名前で作成します。

ref が State、computed が Gettes、function が Actionsに対応します。

import { defineStore } from 'pinia'
import { ref } from 'vue'

export const useProfileStore = defineStore('profile', () => {
  // State
  const headline = ref('メインタイトル')
  const subtext = ref('ここにサブテキストを入力します。\n改行も保持されます。')

  const socialLinks = ref([
    { url: 'https://github.com/username', label: 'GitHub', iconPath: '/icons/github.png' },
    { url: '#', label: 'X', iconPath: '/icons/x.svg' },
    { url: '#', label: 'Instagram', iconPath: '/icons/instagram.svg' },
  ])

  return { headline, subtext, socialLinks }
})

4. コンポーネントでの利用

作成したストアをコンポーネントでインポートして利用します。
v-for を使うことで、テンプレートを動的かつシンプルに保つことができます。

<template>
  <section class="hero min-h-screen flex flex-col justify-center items-center text-white">
    <div class="text-center px-4">
      <h1 class="text-4xl font-bold mb-4">{{ profile.headline }}</h1>
      <p class="text-lg mb-8 whitespace-pre-wrap">{{ profile.subtext }}</p>

      <div class="flex justify-center gap-4 mt-2">
        <SocialIcon
          v-for="link in profile.socialLinks"
          :key="link.label"
          :url="link.url"
          :label="link.label"
          :iconPath="link.iconPath"
        />
      </div>
    </div>
  </section>
</template>

<script setup lang="ts">
import { useProfileStore } from '../stores/profile'
import SocialIcon from './SocialIcon.vue'

const profile = useProfileStore()
</script>

5. Reactと比較してのメリットとは

一般的に、React(ReduxやContext API)と比較した際のPiniaのメリットとして以下の点が挙げられます。

  1. ボイラープレートが圧倒的に少ない: ReduxのようにAction TypesやReducerを細かく分ける必要がなく、直感的に記述することができる

  2. TypeScriptとの親和性: Setup Store形式だと、特別な設定なしで型推論が強力に効くため、型安全な開発が容易であること

  3. 関心の分離が容易: コンポーネントに直書きしていたデータをストアに逃がすことで、テンプレートの視認性の向上やロジックの再利用がしやすくなる

まとめ

Piniaを導入することで、ポートフォリオのデータを一括管理できるようになり、保守性が向上しました。
今後は、プラウザをリロードしても状態が消えない「永続化(pinia-plugin-persistedstate)」や、より複雑な非同期処理の管理にも挑戦してみたいと思います。

この記事が少しでも参考になれば幸いです!

0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?