【Vuex/Store】gettersとmapGettersの使い方 / index.js以外の呼び出し方.

gettersとmapGettersの利用方法を解説していきます。

Q. gettersの利用目的とは

gettersはなぜ利用するのでしょうか。

Storeで状態をもつ変数としてstateがあります。stateにアクセスすればgettersを必ずしも利用する必要はありません。ただし、gettersを利用するべきシチュエーションがあります。

それは、stateの値を基に他のデータへと処理したい場合です。

例えば、stateに配列データを含んで、gettersでは条件を基に配列をフィルター処理してデータ提供したい場合などです。

公式サイトの説明でも紹介されています。

Q. gettersの記述方法

gettersのStore内での記述方法

ここでは、簡単な処理にします。 stateのidを+1するgettersを記述します。

export const state = () => ({
  id: 0,
  })
  
  export const getters = {
    idplus(state) { // satateを引数に持つ
      return state.id + 1 // gettersの処理
    },
  }

Q. gettersの呼び出し方法

A. index.js に記述されているsotre -> gettersの場合
    <div>
      {{ $store.getters.idplus }}
    </div>
A. index.js 以外記述されているsotre -> gettersの場合 

ここでは、store/me.js に記述されているstoreとします。

    <div>
      {{ $store.getters['me/idplus'] }}
    </div>

Q. mapGettersの目的

gettersを呼び出す際に、記述が冗長になりがちです。
各Vueファイル上で、gettersを繰り返す呼び出す場合やコード記述量を減らしたい場合に利用します。

Q. mapGettersの記述方法

gettersを記述していれば、呼び出せます。 mapGettersのための記述は必要ありません。

Q. mapGettersの呼び出し方法

Vueファイル script内にて

import { mapGetters } from 'vuex'
A. index.js に記述されているsotre -> gettersの場合
  computed: {
    ...mapGetters({ idplus:  'idplus', // idplusで命名
    })
  },
A. index.js に記述されているsotre -> gettersの場合

ここでは、store/me.js に記述されているstoreとします。

  computed: {
    ...mapGetters({ idplus:  'me/idplus', // idplusで命名
    })
  },

idplusで命名しているので、下記で呼び出します。

    <div>
      {{ idplus }}
    </div>

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 )

axios.postの401error時は引数を確認

今回はaxiosの処理詳細については解説しません。

axiosでのリクエスト時に、設定が間違っていないのに401 (Unauthorized) errorになってしまう方へ。

確認として、引数の順番が間違っていないかを確認しましょう。

  • post : 
    • 第一引数:url
    • 第二引数:data 
    • 第三引数:config (header情報など)

例えば、下記のような処理です。
これが、第二引数、第三引数を順番間違えると 正しくリクエストされず(header情報として、payloadを渡してしまう。)

this.$axios.$post('/api/test',
  payload,
  { headers: { Authorization: `Bearer ${access_token}` },
})
  .then(res => console.log(res))
  .catch(error => console.log(error))     

getや他のメソッドに関しても下記に詳しく載っています。

【axios】HTTPリクエストメソッド別の引数一覧表(エイリアスを使用した場合)

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>

Promiseオブジェクト.分からないことから考える編 / JavaScript/Vue.js

非同期処理を実行する際に利用する Promiseオブジェクト.
何となく分かるが、実際にコードを書いてみようとすると困ってしまう。という状況有りませんでしょうか。
何かが分かっていないが、何が分かっていないのか….という状況でした。

疑問として湧いてきたことをベースに、Promiseオブジェクトについてまとめていきたいと思います。

Q1:Promiseオブジェクトとは?

Promiseオブジェクトを単純に表現すると、状態を持つオブジェクトです。
3つの状態があります。
保留中(pending)
・成功(fulfilled)
・失敗(reject)

Promiseオブジェクトは常に3つのどれかの状態を持ちます。
これらの状態を持つという特徴があるからこそ、非同期処理を作ることが出来ます。

Q2:Promiseの状態はいつ変わる?

成功するか、失敗するかで、状態が変わります。
そのまんま過ぎますかね。では、次へ。

Q3:Promiseの成功 / 失敗はどう決まる?

非常に単純化すると、resolveが実行されたら成功・rejectが実行されたら失敗です。

Promiseオブジェクトの中身をconsoleで確認していきます。

conosole 結果 / 保留中(pending)
const promise = new Promise( (resolve, reject ) => {
      })
console.log(promise);
Promise {<pending>}
[[Prototype]]: Promise
[[PromiseState]]: "pending"
[[PromiseResult]]: undefined

Promiseオブジェクトは、[PromiseState] , [PromiseResult] の2つを持ちます。

上記では、PromiseStateはpendingとなっています。状態が何も変わっていない初期状態です。

conosole 結果 / 成功(fulfilled)

次に、Promiseの中でresolveを実行してみます。

const promise = new Promise( (resolve, reject ) => {
        resolve();
      })
console.log(promise);
Promise {<fulfilled>: undefined}
[[Prototype]]: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: undefined

resolve()が実行されたPromiseは成功(fulfilled)の状態に変化しています。

conosole 結果 / ・失敗(reject)

次は予想がつくかと思いますが、
Promiseの中でrejectを実行してみます。

const promise = new Promise( (resolve, reject ) => {
        reject();
      })
console.log(promise);
Promise {<rejected>: undefined}
[[Prototype]]: Promise
[[PromiseState]]: "rejected"
[[PromiseResult]]: undefined

成功のときと同様に
reject()が実行されたPromiseは失敗(reject)の状態に変化しています。

Q4:あれ? resolve, reject って、何?

ここで、ふと思ったのはresolve, reject って何だろうということでした….

結論から言うと、Promiseオブジェクトの
・第一引数:resolve
・第二引数:reject
※両方とも関数です。

名称は何でもOKで、第一引数に指定した関数が実行されれば成功、第二引数に指定した関数が実行されれば失敗  ※reject(第二引数)は省略が可

consoleで確認します。

const promise = new Promise( (daiichiHikisu, reject ) => {
  daiichiHikisu();
})
console.log(promise);
Promise {<fulfilled>: undefined}
[[Prototype]]: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: undefined

resolve()を実行したときと同じく、成功(fulfilled)となっています。

つまり、名称は何でもOKで、第一引数に指定した関数が実行されれば成功となるのです。

Q5:PromiseResultは何?

Q4まで、PromiseオブジェクトのPromiseStateについて調べてきました。その間、PromiseResultは全てundefinedでした。

PromiseResultは、resolve OR rejectで返す値です。

const promise = new Promise( (resolve, reject ) => {
  resolve("success");
})
console.log(promise);
Promise {<fulfilled>: 'success'}
[[Prototype]]: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: "success"

resolve()で返した値が、PromiseResultに含まれます。

Q6:で、非同期処理とPromiseオブジェクトの関係とは?

Promiseオブジェクトは、PromiseStateが変わることで状態が変化することはよく分かりました。結局、Promiseオブジェクトが非同期処理をどの様に実現するのでしょうか。

非同期処理を実現するために、Promiseオブジェクトの処理に大事なメソッドがあります。それは、then()と catch()です。

then(): Promiseの結果、fulfilledの場合に実行
catch(): Promiseの結果、rejectの場合に実行

実際に、consoleで確認します。

const promise = new Promise( (resolve, reject ) => {
  resolve();
})
  .then(() => {
    console.log("resolveしたよ");
  })
  .catch(() => {
    console.log("rejectしたよ");
  });

conosole 結果 / 成功(fulfilled)

resolveしたよ

逆に、rejectの場合

const promise = new Promise( (resolve, reject ) => {
  reject();
})
  .then(() => {
    console.log("resolveしたよ");
  })
  .catch(() => {
    console.log("rejectしたよ");
  });

conosole 結果 / ・失敗(reject)

rejectしたよ

となります。
下記の通りにthen, catchがそれぞれ実行されます。

then(): Promiseの結果、fulfilledの場合に実行
catch(): Promiseの結果、rejectの場合に実行

Q7:ででで、結局、非同期処理とPromiseオブジェクトの関係とは?

結局のところ、これで非同期処理をどうやって実現するのでしょうか。

・Promiseオブジェクトは状態を持つ
・状態に合わせて処理を変更できる

この2つの特性を利用して、非同期処理を実現することが出来ます。

setTimeout関数を利用して、1000ms後にresolve(“success”)を実行する関数を作ります。returnでPromiseオブジェクトを返します。

promiseAfter1000ms() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("success")
    }, 1000)
  })
}

そして、この関数の実行に対してthen(), catch()で状態に合わせて処理を実行します。

this.getValueAfter1000ms()
      .then(() => { console.log("good") })
      .catch(() => { console.log("error") })
conosole 結果 / 成功(fulfilled)

Promiseオブジェクトが成功(fulfilled)の際に実行されるthen()内のconsoleが、1000ms後に処理されます。

good
conosole 結果 / ・失敗(reject)

次に、reject処理が実行されるPromiseへ変更すると

promiseAfter1000ms() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject("misstake")
    }, 1000)
  })
}

catch()内のconsoleが、1000ms後に処理されます。

error

Q8:より実践的に、Promiseオブジェクトで非同期処理を実行するには?

Q7にて、1000ms後に、Promiseの状態に応じて実行する非同期処理を記述しました。しかし、分かったような分からないような、使いみちがイメージしづらいかもしれません。

より実践的な処理にてイメージを掴みましょう。

サーバーにPostリクエストした後に、そのレスポンスデータが返ってきた後に実行する非同期処理を考えてみます。

サーバーにPostする処理をaxiosを使って書いていきます。
axiosとは、axiosの設定については触れません。
既知ではない方は、サーバーにリクエストしている。くらいに思っておいて下さい。

Promiseオブジェクトの中に axios処理を記述しています。

getServerData() {
  return new Promise( (resolve, reject) => {
    this.$axios.$post('/api/ques', { name: "test",}) // axios処理
     .then(res => resolve( res ))
     .catch(res => reject( res ))
  })
},

補足

※Postリクエストにて、nameプロパティに文字列testを送信
※axios処理自体も非同期処理になっている
※axios処理が成功した場合(fulfilled)、レスポンスでresが返ってくる

上記のaxiosによりPostする処理の結果を受けて、非同期処理を実行します。

axiosによるPostリクエストが成功した場合、thenが実行されます。失敗した場合にはcatchが実行されます。

this.getServerData()
      .then((res) => { console.log(res) })
      .catch((res) => { console.log(res) })

■参考にさせて頂いた情報

  1. https://www.tohoho-web.com/ex/promise.html
  2. https://qiita.com/cheez921/items/41b744e4e002b966391a
  3. https://hidekazu-blog.com/javascript-promise

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

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

Vue.jsのemitで複数のデータを送受信する方法

メモ書きになってしまいます。

複数データを送る:子 Componet の<script>

<script>
export default {
  data() {
    return {
      email: "",
      password: "",      
    };
  },  
  methods: {
    onSubmit() {      
      this.$emit('formSubmit', 
                  {
              email: this.email,
              password: this.password,
            });
    },
    onInputEmail(e) {
      this.email = e.target.value;
    },
    onInputPassword(e) {
      this.password = e.target.value;
    },
  },
</script>

複数データ受け取る:親

<template>
//省略
      <SimpleForm @formSubmit="onSubmit"/>
//省略
</template>


<script>
import SimpleForm from "./components/SimpleForm.vue"

export default {
  name: 'App',
  components: {
    SimpleForm,
  },
  methods: {
    onSubmit({email, password}) {

      console.log(email)
      console.log(password)

//dataでemail, passwordを作る必要なし.
      this.msg = "//email:" + email + "//password:" + password;
    }
  },
  data() {
    return {
      msg: 'Emai/Passwordを反映',
    }
  },
}
</script>

【超初学者向け】Vue.jsでデータを親子で送受信

Vue.jsを触り初めて2日目です。 結構苦戦しています。
データのやり取りがイメージが曖昧なことが影響しているかと思います。

formデータを 子 Component → 親Component 渡す方法を紹介します。
ただし、記述方法としては、ベストなものではないです。 それでも、無理矢理にでもデータを受け渡すことで、Vue.jsの肌触り感に慣れていける方が重要かなと思っています。

①: emitの理解

②:子のComponet<Input>データを親に渡す

最初のSTEPとして、Componet<Input>データを親に渡してみます。

App.vue
<template>
  <div id="app">

       <!-- Componetの呼び出し && parentMethodでComponentのemitからのデータを受け取る -->
      <InputData class="input-data" @input-data="parentMethod"/>

       <!-- Inputで入力されたデータがリアルタイムで反映 -->
      <div>
        {{ this.input_data_single }}        
      </div>

  </div>
</template>

<script>
import InputData from "./components/InputData.vue"

export default {
  name: 'App',
  components: {
    InputData,
  },
  methods: {
    parentMethod(e){
      console.log(e);
      this.input_data_single = e;
    },
  },
  data() {
    return {
      input_data_single: '',
    }
  },

}
</script>

<style>
/* 省略 */
</style>

InputData.vue ( 子 Componet )
<template>
  <div>
    <input type="text" :value="value" @input="childMethod">
  </div>
</template>

<script>
export default {
  methods: {
    childMethod(e) {
      console.log(e.target.value);
      this.$emit('input-data', e.target.value);
    },
  },
  data() {
    return {
      value: "",      
    };
  },
};
</script>

<style>
/* 省略 */
</style>

Request後にFormRequestのバリデーションデータを操作する

標題の通りですが、どのような機会に必要でしょうか。

私が遭遇した場面ですと、POST Requestにはuser_idを含めない but バリデーションrulesの中で、user_idを利用したい場合です。
例えば、category_idとuser_idの掛け合わせた場合のUnique処理などです。

validationData()を利用.

FormRequestのクラス内でvalidationDataを使うとバリデーションデータを変更可能 ※ただし、Requestデータが変更される訳ではないのでご注意を。

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
use Illuminate\Support\Facades\Auth;

class CommentRequest extends FormRequest
{
    //
    //省略
    //
    protected function validationData()
    {
        $data = $this->all();
        $data['user_id'] = Auth::id();

        // dd($data); // $dataを確認して見て下さい。

        return $data;
    }

    public function rules()
    {
        $user_id = $this->validationData()['user_id']; //validationData()を呼び出しています。

        return [
            'comment' => 'required',
            'category_id' => 
                ['required',Rule::unique('comments', 'channel_id')->where('user_id', $user_id)],            
          ];
    }    

    //
    //省略
    //

}

他のメソッドも合わせて紹介されている下記、ご参考に!
※ メソッドをpublic指定して下さいとErrorが出たので、ご注意を。

FormRequestでバリデーションを行う前に値を操作する