VuexにContentfulの型定義ファイルとnuxtServerInitを追加しよう
  • 2022.01.12に公開
  • ブログ構築TS
  • 6. Vuex×TypeScriptセットアップ
  • No.3 / 4

今回達成すること

VuexにContentfulの型定義ファイルを作成し、stateの型付けを行います。

型定義ファイルを作成する

Vuexストアの型定義ファイルは、storeディレクトリ直下のtypesディレクトリ内に作成します。

% mkdir store/types && touch $_/index.ts

Vuexストアの型定義

作成したstore/types/index.tsには、Vuexで使用する型定義ファイルを格納します。

今後、コードが増えてきたり別のVueファイルの型定義を行う場合は、このstore/typesディレクトリにファイルを追加していきます。

完全にローカルで使用する型は、そのtsファイルに定義します。

Contentfulのインターフェースを定義する

types/index.tsにContentful共通のインターフェースを定義します。

  • コンテンツIDなどが格納されているContentfulSys
  • メディアイメージのContentfulImageの型を定義します。
store/types/index.ts
export interface ContentfulSys {
  id: string
  createdAt: string
  updatedAt: string
  sys: {
    id: string
  }
  contentType: {
    sys: {
      id: string
    }
  }
}

export interface ContentfulImage {
  fields: {
    title: string
    file: {
      url: string
      details: {
        image: {
          width: number
          height: number
        }
      }
    }
  }
}

Contentfulモデルの型をfirldsプロパティに追加します。

筆者はBlogCategoryBlogTagを定義します。

ここはご自身のモデルフィールドに合わせてください。

store/types/index.ts
export interface BlogCategory {
  sys: ContentfulSys
  fields: {
    // Not Required
    image?: ContentfulImage
    title: string
    description: string
    sort: number
    slug: string
    isMain: boolean
  }
}

export interface BlogTag {
  sys: ContentfulSys
  fields: {
    // Not Required
    image?: ContentfulImage
    title: string
    slug: string
  }
}
  • image? ... Contentful上で必須プロパティでない場合は、?を付けてundefinedを定義する。

    image? = ContentfulImage | undefined

関連づくモデルのインターフェース

関連するモデルはプロパティ名にインターフェースを指定します。

1対多の関連付けは配列で定義します。

store/types/index.ts
export interface BlogPost {
  sys: ContentfulSys
  fields: {
    // Reference 1:1(Required)
    category: BlogCategory
    // Required
    image: ContentfulImage
    title: string
    slug: string
    body: string
    publishDate: string
    // References 1:多(Not Required)
    tags?: BlogTag[]
  }
}
  • publishDate ... ContentfulのDateはString型で返される。

今回のストア設計とnuxtServerInit()の実行場所

今回Contentfulから取得するデータは、全てindex.tsstateに集約します。

これは、サーバーサイドでリクエストを行うnuxtServerInit()を使用するためです。

nuxtServerInit()は、store/inde.tsでしか実行することができません。

そのため、store/inde.tsstateに関連する処理を集約しています。

  • index.ts
    • state ... Contentfulの全データを保管。
    • mutations ... Contentful stateデータの代入処理を記述。
    • actions ... nuxtServerInit()でContentful APIのサーバーサイドリクエスト実行。

APIリクエストを行うActionメソッドについては、モデル単位でファイルを切り分けます。

  • post/index.ts(次回作成)

    • actions ... BlogPostモデルのContentful APIリクエスト処理を記述。

      リクエスト実行はindex.tsnuxtServerInit()内で行う。

Vueストアの型定義

store/index.tsstateに、ブログコンテンツを保管するデータを用意します。

これまでのindex.tsは削除して次に書き換えます。

store/index.ts
// typed-vuex setup: https://typed-vuex.roe.dev/getting-started/getting-started-nuxt
import { getAccessorType, getterTree, mutationTree, actionTree } from 'typed-vuex'
import { BlogCategory, BlogPost, BlogTag } from './types'

export const state = () => ({
  categories: [] as BlogCategory[],
  posts: [] as BlogPost[],
  tags: [] as BlogTag[]
})

type RootState = ReturnType<typeof state>

export const getters = getterTree(state, {})

export const mutations = mutationTree(state, {})

export const actions = actionTree({ state, getters, mutations }, {})

export const accessorType = getAccessorType({
  state,
  getters,
  mutations,
  actions,
  modules: {
    /* sub modules */
  }
})

Mutationの作成

mutationsには以下の関数を追加します。

store/index.ts
export const mutations = mutationTree(state, {
  setCategories (state: RootState, payload: BlogCategory[]) {
    state.categories = payload
  },
  setPosts (state: RootState, payload: BlogPost[]) {
    state.posts = payload
  },
  setTags (state: RootState, payload: BlogTag[]) {
    state.tags = payload
  }
})

Actionメソッドの作成

actions内はnuxtServerInit()メソッドと、Contentfulのデータ取得メソッドを追加します。

nuxtServerInit()の第二引数にはNuxtContextが取得できるので、Context型を@nuxt/typesからインポートします。

store/index.ts
// typed-vuex setup: https://typed-vuex.roe.dev/getting-started/getting-started-nuxt
// 一番上に追加 NuxtContextの型をインポート
import { Context } from '@nuxt/types'
...

export const actions = actionTree({ state, getters, mutations }, {
  // server only
  async nuxtServerInit ({ dispatch }, _nuxtContext: Context) {
    await dispatch('getContentfulApi')
  },
  // Contentful APIリクエストを集約
  async getContentfulApi ({ dispatch }) {
    await dispatch('post/getEntries')
  }
})

最終的なstore/index.ts

最終的にstore/index.tsはこのようになります。

store/index.ts
// typed-vuex setup: https://typed-vuex.roe.dev/getting-started/getting-started-nuxt
import { Context } from '@nuxt/types'
import { getAccessorType, getterTree, mutationTree, actionTree } from 'typed-vuex'
import { BlogCategory, BlogPost, BlogTag } from './types'

export const state = () => ({
  categories: [] as BlogCategory[],
  posts: [] as BlogPost[],
  tags: [] as BlogTag[]
})

type RootState = ReturnType<typeof state>

export const getters = getterTree(state, {})

export const mutations = mutationTree(state, {
  setCategories (state: RootState, payload: BlogCategory[]) {
    state.categories = payload
  },
  setPosts (state: RootState, payload: BlogPost[]) {
    state.posts = payload
  },
  setTags (state: RootState, payload: BlogTag[]) {
    state.tags = payload
  }
})

export const actions = actionTree({ state, getters, mutations }, {
  // server only
  async nuxtServerInit ({ dispatch }, _nuxtContext: Context) {
    await dispatch('getContentfulApi')
  },
  // Contentful APIリクエストを集約
  async getContentfulApi ({ dispatch }) {
    await dispatch('post/getEntries')
  }
})

export const accessorType = getAccessorType({
  state,
  getters,
  mutations,
  actions,
  modules: {
    /* sub modules */
  }
})

今回の作業は以上です。

% git add -A
% git commit -m "Add type file to store directory" -m "Add contentful data to vuex store"

次回は?

今回はVuexにContentfulの型とstateを用意しました。

次回は、このstateにContentful APIで取得したコンテンツを代入し、Vueファイルで表示します。

あなたの力になれること
私自身が独学でプログラミングを勉強してきたので、一人で学び続ける苦しみは痛いほど分かります。そこで、当時の私がこんなのあったら良いのにな、と思っていたサービスを立ち上げました。周りに質問できる人がいない、答えの調べ方が分からない、ここを聞きたいだけなのにスクールは高額すぎる。そんな方に向けた単発・短期間メンターサービスを行っています。
独学プログラマのサービス
ブログ構築TSの投稿
1
  • Nuxt.js×TypeScript開発環境構築
  • /
  • #01
Nuxt.jsをローカルPCに立ち上げよう
2
  • Nuxt.js×TypeScript開発環境構築
  • /
  • #02
Nuxt.jsプロジェクトをGitHubにPushしよう
3
  • Nuxt.js×TypeScript開発環境構築
  • /
  • #03
nuxt-property-decoratorのインストールとTypeScriptのセットアップ
1
  • Vuetifyセットアップ
  • /
  • #01
TypeScript環境のNuxt.jsにVuetifyを導入しよう
2
  • Vuetifyセットアップ
  • /
  • #02
VuetifyにカスタムCSSを追加してSASS変数を理解しよう
3
  • Vuetifyセットアップ
  • /
  • #03
VuetifyにカスタムSVGアイコンを追加しよう
1
  • NetlifyCLIを使ったNuxtデプロイ
  • /
  • #01
Netlify CLIをインストールして本番環境のサイトを作成しよう
2
  • NetlifyCLIを使ったNuxtデプロイ
  • /
  • #02
netlify.tomlを使ってNuxt.jsをNetlifyに手動デプロイしよう
1
  • Contentfulモデル構築
  • /
  • #01
Contentfulの料金とCommunityプランの無料枠を理解する
2
  • Contentfulモデル構築
  • /
  • #02
Contentfulへ新規会員登録、ロケールの変更、API Keyの発行を行う
3
  • Contentfulモデル構築
  • /
  • #03
Contentful ブログカテゴリーモデルを作成しよう
4
  • Contentfulモデル構築
  • /
  • #04
Contentful カテゴリーモデルに1対1で関連づくblogPostモデルを作成しよう
5
  • Contentfulモデル構築
  • /
  • #05
Contentful ブログ記事に1対多で関連づくplogTagモデルを作成しよう
6
  • Contentfulモデル構築
  • /
  • #06
Contentful カテゴリー・ブログ記事・タグコンテンツを作成しよう
1
  • Nuxt.js×Contentfulセットアップ
  • /
  • #01
Nuxt.js×Contentfulセットアップ。モジュールのインストールからAPI Keyの登録まで
2
  • Nuxt.js×Contentfulセットアップ
  • /
  • #02
Contentful APIリクエストの実行 Nuxt.jsにブログコンテンツを表示しよう
3
  • Nuxt.js×Contentfulセットアップ
  • /
  • #03
ContentfulAPIをNetlifyにデプロイしよう【Nuxt FullStaticのasyncDataとfetch】
1
  • Vuex×TypeScriptセットアップ
  • /
  • #01
Vuexの型付け vuex-module-decoratorsとnuxt-typed-vuexどちらを使用するか
2
  • Vuex×TypeScriptセットアップ
  • /
  • #02
nuxt-typed-vuexのインストールとセットアップ。Vuexの型定義と呼び出し方
3
  • Vuex×TypeScriptセットアップ
  • /
  • #03
VuexにContentfulの型定義ファイルとnuxtServerInitを追加しよう
4
  • Vuex×TypeScriptセットアップ
  • /
  • #04
VuexにContentfulAPIレスポンスを保存してVueファイルに表示しよう
1
  • コンテンツページ構築
  • /
  • #01
ブログアプリのページ設計とNuxt.jsの動的ルーティングについて理解しよう
2
  • コンテンツページ構築
  • /
  • #02
カテゴリーのコンテンツページを作成しよう【Nuxt.js×Contentful】
3
  • コンテンツページ構築
  • /
  • #03
カテゴリーに関連付くブログ記事一覧を表示しよう【Nuxt.js×Contentful】
4
  • コンテンツページ構築
  • /
  • #04
injectを使用して共通エラー処理メソッドを作成しよう【Nuxt×TypeScript】
5
  • コンテンツページ構築
  • /
  • #05
NuxtChildを使用してブログ記事ページを作成しよう【Nuxt.js×TypeScript】
6
  • コンテンツページ構築
  • /
  • #06
タグ一覧ページとタグ関連づく記事一覧を表示しよう【Nuxt.js×TypeScript】
7
  • コンテンツページ構築
  • /
  • #07
プライバシーポリシーページを作成しよう【Nuxt.js×TypeScript】
8
  • コンテンツページ構築
  • /
  • #08
@nuxtjs/i18nのインストールとセットアップ。ページタイトルの翻訳化【TypeScript】
1
  • NetlifyFunctionsを使った検索機能
  • /
  • #01
Netlify Functionsを使ってクエリを返す関数を作成しよう【Nuxt.js×TypeScript】
2
  • NetlifyFunctionsを使った検索機能
  • /
  • #02
Netlify Functionsプロジェクトをデプロイしよう【Nuxt.js×TypeScript】
3
  • NetlifyFunctionsを使った検索機能
  • /
  • #03
Nuxt.js × axiosセットアップ Netlify Functionsにリクエストを行う準備をしよう
4
  • NetlifyFunctionsを使った検索機能
  • /
  • #04
オリジン•CORS•プリフライトリクエストを理解する【Nuxt.js×Netlify Functions】
5
  • NetlifyFunctionsを使った検索機能
  • /
  • #05
Netlify Functionsを使ってフォームバリデーション機能を構築しよう【Nuxt.js】
6
  • NetlifyFunctionsを使った検索機能
  • /
  • #06
ツールバーに表示する検索フォームを作成しよう【Nuxt.js×TypeScript】
7
  • NetlifyFunctionsを使った検索機能
  • /
  • #07
検索ページを作成しよう【Vue propsとTypeScriptの書き方 解説】
8
  • NetlifyFunctionsを使った検索機能
  • /
  • #08
Netlify FunctionsからContentfulAPIリクエストを送ろう【Nuxt.js】
9
  • NetlifyFunctionsを使った検索機能
  • /
  • #09
検索ページに「もっと見る」ボタンを実装しよう【Nuxt.js×TypeScript】
1
  • ブログMarkdown対応
  • /
  • #01
@nuxtjs/markdownitのインストールとセットアップ【Nuxt.js×TypeScript】
2
  • ブログMarkdown対応
  • /
  • #02
Nuxt.js×markdown-it 外部リンクを別タブで開くプラグインを追加しよう
3
  • ブログMarkdown対応
  • /
  • #03
Nuxt.js×markdown-it 内部リンクをVueRouterで高速にページ遷移しよう
4
  • ブログMarkdown対応
  • /
  • #04
Nuxt.js×markdown-it アンカーリンクとブログ目次を自動生成しよう
独学プログラマ
独学でも、ここまでできるってよ。
CONTACT
Nuxt.js制作のご依頼は下記メールアドレスまでお送りください。