[Nuxt.js/Vuex] store/index.js”以外”のファイルへアクセスする方法

Nuxt.jsにて、Vuexを利用する際にstore/index.jsはデフォルトで設定されております。
基本的にはこちらのindex.jsにVuexの処理を記述していくことになります。が、index.js以外のファイルに分割して管理したいケースが発生すると思います。

今回は、Nuxt.js において store/index.js以外のファイルにアクセスする方法を解説します。

前提

今回はstoreの記述方法は解説しません。index.js以外に記述するとしても、index.jsへの記述方法と同様です。

todo.jsがstore配下に存在し、こちらにアクセスしていく方法を考えています。

store
 L index.js
 L todos.js

Q. stateの場合

this.$store.state.{ファイル名}.{state名}

例:

this.$store.state.todos.list

Q. mutationsの場合

this.$store.commit(“{ファイル名}/{mutations名}”)

例:

this.$store.commit('todos/add', e.target.value)

Q. actionsの場合

this.$store.dispatch(“{ファイル名}/{actions名}”)

例:

this.$store.dispatch('todos/addList')

Q. gettersの場合

下記、記事にまとめております。

[Nuxt×Laravel] API通信のValidationをLaravelで処理する方法

Nuxt×Laravel でアプリケーションを作成する際に、バックエンド側のLaravelでValidationを設定する方法を紹介します。

幾つか設定方法がありますが、今回は下記の方法にてValidationを設定していきます。

  1. Laravel >> FormRequestを作成
  2. Laravel >> FormRequestのrulesを設定
  3. Laravel >> FormRequest内で、failedValidationをオーバーライド
  4. Laravel >> Postリクエスト内にFormRequestを適用
  5. Nuxt >> APIレスポンスにて、Validationメッセージを取得

0. 前提

NuxtからのAPIリクエストは axiosを利用しています。axiosに利用方法に関して詳細は省きます。

1. Laravel >> FormRequestを作成

コマンドで生成します。

php artisan make:request PostRequest // PostRequest部分は任意. FormRequestの命名

コマンドによって下記ファイルが生成されます。

server/app/app/Http/Requests/PostRequest.php
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class PostRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return false;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
        ];
    }
}

2. Laravel >> FormRequestのrulesを設定

Validationのrulesを設定していきます。

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class PostRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true; // trueへ変更
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'user_id' => 'required',
            'post_id' => 'required',
        ];
    }
}
'user_id'、'post_id'が必須というシンプルなrulesにしておきます。

3. Laravel >> FormRequest内で、failedValidationをオーバーライド

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class PostRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true; // trueへ変更
}

/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'user_id' => 'required',
'post_id' => 'required',
];
}

/**
* [override] バリデーション失敗時ハンドリング
*
* @param Validator $validator
* @throw HttpResponseException
* @see FormRequest::failedValidation()
*/
protected function failedValidation( Validator $validator )
{
$response['data'] = [];
$response['status'] = 'NG';
$response['summary'] = 'Failed validation.';
$response['errors'] = $validator->errors()->toArray();

throw new HttpResponseException(
response()->json( $response, 422 )
);
}
}

FormRequestファイル内に、failedValidationを追加しました。

これによって、下記のファイル > メソッドをオーバーライドします。

server/app/vendor/laravel/framework/src/Illuminate/Foundation/Http/FormRequest.php > failedValidation()

また、failedValidation()がいつ呼び出されるかというと。下記です。

server/app/vendor/laravel/framework/src/Illuminate/Validation/ValidatesWhenResolvedTrait.php > validateResolved()

4. Laravel >> Postリクエスト内にFormRequestを適用

FormRequestをContollerのメソッドに適用します。

    public function postAction(PostRequest $request) { // 適用
        //省略
        //user_id, post_id が受け取る
    }

apiのroute

server/app/routes/api.php
<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;


/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/

Route::post('postAction', [任意のController::class, 'postAction']);
    
});

5. Nuxt >> APIレスポンスにて、Validationメッセージを取得

const payload = {
  user_id: XXXX,
  post_id: YYYY,
};
const access_token = ZZZZ;
this.$axios.$post('/api/postAction', payload , { headers: { Authorization: `Bearer ${access_token}` } })
    .then(
      res => {
          console.log(res);
      }
    )
    .catch(error => {
      console.log(error.response.data);
      })

APIリクエスト/レスポンスの処理のみ記載しています。

レスポンスを受け取る際は、error.response で受け取ります。

Nuxtのcontextとは. contextへアクセスを実験

Nuxtのcontext(コンテキスト)について解説 / 実験していきます。

細かく・正確な解説はNuxtの公式サイトを確認頂けたらと思います。
が、
実際にcontextを呼び出して中身を確認しつつ、アクセス方法を実験していきたいと思います。

Q. Nuxtのcontext(コンテキスト)とは

Vueオブジェクトのプロパティ、メソッドへアクセス、操作可能な変数です。
特定のライフサイクル内でのみ利用可能です。
(極端に解釈すると、特定の場所から呼び出せるグローバルなNuxt(Vue)情報を含んだ変数です。)

context内には様々な情報を含んでいます。 様々なキー

注意 「Nuxtのcontext」と「Vuexのcontext」は別物なので混合しないようにしてください。

Q. Nuxtのcontextを呼び出す場所

context は、Nuxt から Vue コンポーネントに追加のオブジェクト/パラメータを提供し、asyncData 、fetch 、plugins 、middleware そして nuxtServerInit のような特別な Nuxt ライフサイクル内で使用できます。

https://develop365.gitlab.io/nuxtjs-2.8.X-doc/ja/api/context/

上記あるように「asyncData 、fetch 、plugins 、middleware 、nuxtServerInit」からcontextを呼び出すことが出来る。

Q. Nuxtのcontextを呼び出す方法

では、実際にcontextを呼び出してみます。

上記のライフサイクルのみで呼び出し可能です。

A, fetchから呼び出す。Component内(ページ、レイアウトカラム内でも)
<script>
export default {
  // 省略
  fetch(context) {
    console.log(context);
  },
  // 省略
}
</script>

下記のような結果が取得出来ました。
インストールしているライブラリなどによってもcontextで取得できる内容は変わります。

$axiosƒ wrap()
$config: {_app: {…}}
$vuetify: {…}
app: {head: {…}, store: Store, router: VueRouter, nuxt: {…}, render: ƒ, …}
base: "/"
env: {}
errorƒ ()
from: {name: 'index', meta: Array(1), path: '/', hash: '', query: {…}, …}
isDev: true
isHMR: false
isStatic: false
nextƒ ()
nuxtState: {config: {…}}
params: {}
payload: undefined
query: {}
redirectƒ (status, path, query)
route: {name: 'index', meta: Array(1), path: '/', hash: '', query: {…}, …}
store: Store {_committing: false, _actions: {…}, _actionSubscribers: Array(1), _mutations: {…}, _wrappedGetters: {…}, …}
_errored: false
_redirected: false
A, middlewearから呼び出す。
app/middleware/test.js
export default function(context){
  console.log(context);
}
app/layouts/default.vue

layoutのmiddlewearにtest.jsを適用

<script>
  export default {
//省略
  middleware: ['test'],
//省略
</script>

同じ結果が取得出来ました。

Q. 指定のライフサイクル以外で取得は不可?

出来ません。mountedから呼び出してみます。

<script>
export default {
  // 省略
  mounted(context) {
    console.log(context);
  },
  // 省略
}
</script>

結果は undefined が返ってきます。

Q. contextデータ大きすぎて、使いづらい?

分割代入を利用することで、必要なデータのみを取得することが可能です。

例えば、context内に存在する、appオブジェクトのみを取得したい場合には、下記のように分割代入で取得

A, fetchから呼び出す。Component内(ページ、レイアウトカラム内でも)
<script>
export default {
  // 省略
  fetch({app}) {
    console.log(app);
  },
  // 省略
}
</script>

下記のようなappの中身のみ取得

{head: {…}, store: Store, router: VueRouter, nuxt: {…}, render: ƒ, …}
$axiosƒ wrap()
$config: {_app: {…}}
beforeCreateƒ beforeCreate()
components: {NuxtLoading: {…}}
computed: {isOffline: ƒ, isFetching: ƒ}
context: {isStatic: false, isDev: true, isHMR: false, app: {…}, store: Store, …}
createdƒ created()
dataƒ data()
head: {title: 'app', htmlAttrs: {…}, meta: Array(4), link: Array(3), style: Array(0), …}
methods: {refreshOnlineStatus: ƒ, refresh: ƒ, errorChanged: ƒ, setLayout: ƒ, loadLayout: ƒ}
mountedƒ mounted()
nuxt: {…}
renderƒ render(h, props)
router: VueRouter {app: Vue, apps: Array(1), options: {…}, beforeHooks: Array(2), resolveHooks: Array(0), …}
store: Store {_committing: false, _actions: {…}, _actionSubscribers: Array(1), _mutations: {…}, _wrappedGetters: {…}, …}
vuetify: Vuetify {framework: {…}, installed: Array(7), preset: {…}, userPreset: {…}}
watch: {nuxt.err: 'errorChanged'}
[[Prototype]]: Object

Vue.js学び始めのエンジニアがStoreへの理解を共有

今回の投稿に関しては、誤りも含まれている可能性があります。
Vueを学び初めて間もないため、理解不足な点があると思います。それでも、あえて記述しておきたいのは、理解が浅いからこそ湧いてくる疑問が結構あると思ったからです。 もしかすると、他の初学者の方も似た疑問にぶつかっている可能性もあるかな?と思います。理解を深めていく一助になればと思い残しておきます。

Q:Storeとは.

Vueアプリケーションのどこからでもアクセス出来るデータ保管/データ処理できる仕組み.

正式な解説はこちら

Q:何のためにStoreが存在するのか.

アプリケーション全体で管理するほうが効率的なデータを管理するため.例えば、ユーザーの認証情報など.

正式な解説はこちら

Q:Storeのもつ機能

state, getters, mutations, actionsというメソッドがある。

state:Storeで保持したいデータ

getters:stateの算出プロパティ

mutations:stateを変更可能なメソッド

actions:非同期処理に対応したメソッド ※多くの場合非同期処理実行後に、mutationsのメソッドを実行

Q:Storeの使い方

正式な解説は

https://vuex.vuejs.org/ja/guide/state.html

適当で簡素なStoreを用いた処理

coming soon

[Vue.js/Nuxt] Storeを複数作成した場合のデータアクセス方法

分かりにくい標題で申し訳ありません。
Storeを利用する場合は、
Storeディレクトリにindex.jsファイルを作成して、state, getters, mutations, actionsを記述していくかと思います。

しかし、index.js以外の情報をStoreで保持したい場合はどうでしょうか。Storeで複数ファイルを利用する方法と、データアクセス方法について解説していきます。

Storeディレクトリの配下を下記とします。 
※me.jsは認証ユーザーの情報を保持するStoreとします。

/* 省略 */
Store
  L index.js
  L me.js

①:stateへのアクセス

まずは、stateへのアクセスについて見ていきたいと思います。

index.jsのstate
export const state = () => ({
    txt: 'texttext',
  })
// state以外省略
me.jsのstate
export const state = () => ({
  id: 0,
  name: 'taro',
  email: 'taro@gmail.com',
  })
// state以外省略

consoleで確認していきます。

任意のComponent内で、下記consoleを実施して下さい。

console.log(store.state);

結果は下記が出力されます。

me: (...)
txt: "texttext"

これは何が出力されたのでしょうか。
ドリルダウンしてme: (…)の中身をクリックしてみると。下記が表示されます。

me: Object
id: 1
name: "taro"
email: 'taro@gmail.com',

つまり、console.log(store.state);はStoreに保持している全てのstateを出力しました。しかし、index.jsファイルと、me.jsファイルではアクセス方法が少し異なります。

①-1;me.jsのstateをダイレクトにアクセス

次に、me.jsのstateをダイレクトにアクセスしてみます。下記のconsoleを呼び出して下さい。

console.log(store.state.me);

結果は下記です。 単純ですね。

id: 1
name: "taro"
email: 'taro@gmail.com',

②:actions, mutationsへのアクセス

それでは、他のメソッドについても見ていきます。

me.jsにてactions, mutationsを定義していきます。

  export const mutations = {
    setMe(state, payload) {
      state.id = payload.id
      state.name = payload.name
    },
  }
  
  export const actions = {
    async setMeActions({ commit, state }, payload ) {
        // console.log(state);
        commit('setMe', payload)
    },
  }

任意のComponent内から、me.js内のactions, mutationsへアクセスする方法は下記です。

store.dispatch('me/setMe' ,payload )
store.commit('me/setMeActions' ,payload )

Nuxt.jsで、遷移する際にデータを送受信する方法

Nuxt.jsで Vue Routerを利用してPage遷移をする際に、データを送受信する方法を解説します。

parmas、query を使ったそれぞれのパターンです。

①:params を使ったPage遷移 with data

paramsを利用する = URLにデータを入れ込みます。
あるあるパターンが、http:://domain/user/{id} みたいなケースでしょうか。

①-1:送信側

<template>
  <div>
      <p @click="showUserDetail">
        {{ユーザー詳細ページへ}}
      </p>
   <div>
</template>

<script>
export default {
  methods: {
    showUserDetail() {

      this.$router.push({
        name: "User-id",
        params: {
          id: id,
        },
      });
    }
  }
}
</script>

①-2:受信側

<template>
  <div>
      <p>
        {{this.$route.params}} // paramsの中に含まれる
      </p>
  </div>
</template>

<script>
</script>

②:query を使ったPage遷移 with data

②-1:送信側

<template>
  <div>
      <p @click="showUserDetail">
        {{ユーザー詳細ページへ}}
      </p>
   <div>
</template>

<script>
export default {
  data () {
    return {
      userName: 'tanaka',
      userAge: 30,
    }
  },
  methods: {
    showUserDetail() {

      this.$router.push({
        name: "User-id",
        params: {
          id: id,
        },
        query: {
          name: this.userName,
          age: this.userAge,
        }
      });
    }
  }
}
</script>

②-2:受信側

<template>
  <div>
      <p>
        {{this.$route.query}} // queryの中に含まれる
      </p>
  </div>
</template>

<script>
</script>

Nuxtの初期状態にlayouts Dirがない? layoutsをカスタマイズする方法

Nuxtインストール初期状態では、layoutsディレクトリがありません。

※ Nuxtのインストール方法によって違う可能性ありますので、ご自身のディレクト構成を確認下さい。

正確にいうと、下記ディレクトリ構成でした。
少し分かりづらいかもですが、.nuxt配下にlayoutsが存在しており、ここのdefalutが反映されている状態でした。

/.nuxt
 L /layouts
  L default.vue
 L *省略*
/componets
/node_modules
/pages
/static
/sotre
*省略*

ルートディレクトリにlayoutsを作成して、layoutのカスタマイズをしていきましょう。

①:layoutsディレクトリを作成

/.nuxt
/componets
/layouts //作成
/node_modules
/pages
/static
/sotre
*省略*

②:layoutのvueを作成

/.nuxt
/componets
/layouts
 L default.vue //作成
 L other.vue //作成
/node_modules
/pages
/static
/sotre
*省略*
/layouts/default.vue
<template>
  <div>

    <div>
    <nuxt/>
    </div>

    <hr>
    <!-- Footer -->
    <footer>
      defaultですよー。
    </footer>
  </div>
</template>

<script>
  export default {
  }
</script>

<style>
  footer {
    padding: 50px 0 65px;
    text-align: center;
  }
</style>

/layouts/other.vue
<template>
  <div>

    <div>
    <nuxt/>
    </div>

    <hr>
    <!-- Footer -->
    <footer>
      otherですよー。
    </footer>
  </div>
</template>

<script>
  export default {
  }
</script>

<style>
  footer {
    padding: 50px 0 65px;
    text-align: center;
  }
</style>

③:layoutを反映

/pages/index.vue へ反映

layout 単数形に注意して下さい。

<template>
  <div>
    <h1>Index.Vue</h1>
  </div>

</template>

<script>

export default {
  layout: "other", // 追記
}
</script>

④:ビルド忘れずに

npm run dev

ビルドを実行した後に確認して下さい。