LoginSignup
2
2

More than 3 years have passed since last update.

備忘録集[Vue.js+Laravel+docker]

Posted at

一つの記事に書く程ではないけれども、
ハマった所を今後同じ所でハマった同志のため、
また物忘れが最近酷いので再度自分がハマらないため
自分が躓いた所を備忘録集として残します。
基本的だけれども見落としやすい所が中心です。

備忘録なので書きなぐりの文章が多いです。
また間違い等があるかもしれないので、
都度修正していきます。

Javascript関連:VueJS,typescript,axios等

1.axiosのdeleteの方法

postとは異なる方法で設定する必要がある。

axios.delete('url',
             params: { foo: 'bar' }
             ).then(
             //以下省略
             );

2.[Vue.js]async,awaitでreturnの結果としてaxiosでgetしたデータを取得する。

下の例はupdateDate関数でaxiosを使っている。
このupdateDate関数は外部から呼び出され、this.Dataの値を更新している。
しかしthisを使用しているので、thisに依存している。
依存を解消するなら、axiosの結果をupdateDataの外で受け取るべき。
しかしaxiosはPromise型なので、thenの内部でreturnを書いても値を返さない。

改善前
methods:{
    updateData(url) {
      //データ取得
      axios
        .get(
          url
        )
        .then(response => {
          this.Data=response;
          //下のように書いてもresponseを返さない
          //return respose;
        })
        .catch(error => {
          console.log(error);
        })
    },
}

そこでasync,awaitを利用し以下のように書き直す。
then以降まで書かないでもaxios.get(url)までで,
結果を返してくれる。

参考:https://github.com/axios/axios

例1.thisをupdateDataの外部に出すことができた.
  mounted: async function() {
    let url = "どこかのurl";
    try {
      this.Data = await this.updateTable(url);
    } catch (err) {
      console.log(err);
    }
  },
  methods: {
    async updateData(url) {
      //axiosでデータ取得.get以降にthenを書かない。
      return axios.get(url);
    }
例2
    async function updateData2(url) {
        try {
          const response = await axios.get(url);
          return response;
        } catch (error) {
          console.error(error);
          return error;
        }
      }

注意:axiosをVue.jsのmounted内部で使っている。
Axiosは例外処理も含めて多用する可能性が高いので、
慣れてきたらaxios等の非同期処理を担うクラスを作成したほうがコードが散乱しないので良い。

3.tr等に普通にtransition-groupしてもアニメーションはつかない

参考:https://jp.vuejs.org/v2/guide/components.html#%E5%8B%95%E7%9A%84%E3%81%AA%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88

htmlの仕様によりliやtr等のタグはtableタグ直下等の特殊な条件でしか処理されない。
なので、tableとtrの間に普通にtransition-groupしてもtr以下が表示されなくなる。

失敗例
<tbody name="table-row">
<transition-group>
<tr v-for="data in showData" class="table-row-item" :key="data.id">  
<!--ここは表示されない.transition-groupをdiv等にしても同じ挙動になる.-->
</tr>
</transition-group>
</tbody>

対策の一例は、tbodyにis="transition-group"をつけること。

tbodyにisをつける回避策
<tbody name="table-row" is="transition-group">
<tr v-for="data in showData.data.data" class="table-row-item" :key="data.title">  

他の対策も複数あるので、必要な時は参考urlを参照。

4.アップロードされた画像ファイルのプレビュー表示方法 + URL.createObjectURLの仕様

画像の出力
    <div class="col-sm-1">
      <img class="icon-image border border-dark" :src="iconimg" />
    </div>

ファイルのアップロードを入力するhtmlタグは省略。
ファイルが入力された後、下のselectedFile関数を通して画像を格納する。

    selectedFile(event) {
      //必要に応じてkeyは変更
      this.iconfile = event.target.files[0];
      //プレビュー用のイメージ格納
      if (this.iconfile.type.startsWith("image/")) {
      //ObjectURLを生成
      this.iconimg = window.URL.createObjectURL(this.iconfile);
      }
    },

以下はjavascriptのcreateObjectURLの仕様の話。

createObjectURL(object)は、
与えられたobjectに対してアクセス可能となるURLを生成している。
このURLはクライアントのブラウザのメモリ上に保存されているblob(いわゆる生のデータ)を参照する。
アップロードされたファイルはクライアント上ではFileオブジェクトで保存されているが、
File自体がblobを継承しているため、createObjectURLでのURL生成が可能となる。
なので、createObjectURL関数の引数となるobjectはfile,blob,MediaSourceのどれかでなくてはならない。
生成されたブラウザを閉じるまでURLは有効。
ただ一度ブラウザに読み込まれればURLは必要ないので、可能ならば削除したほうが良い。
window.URL.revokeObjectURL(file);
でURLの削除が可能。

参考:
https://developer.mozilla.org/ja/docs/Web/API/File
https://qiita.com/azu369yu/items/8998e1e1536a5acfb7b3
https://qiita.com/iLLviA/items/c24f385ca3334c05a682

5.[typescript+Vue.js]子コンポーネントにて、propsを定義する際にはundefinedに注意

参考:https://qiita.com/kyokoshimizu/items/ee6c6e6b905b8aa101fa
参考https://tech-up.hatenablog.com/entry/2019/03/15/152258

前提:vue-property-decoratorをimportしている。

@Prop() public name:string;

のようにVue.jsのpropsをtypescriptで書くと

Property '----' has no initializer and is not definitely assigned in the constructor.

というエラーが出て怒られ、コンパイルができないケースがある。
しかし

@Prop() public name:string = "";

と初期化したらしたで、コンパイルも稼働はするが、コンソールには

Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "propsValue"

とエラーが出てしまう。
この場合、前者はtypescriptのエラーで後者がVue.jsのエラーになる。

原因
typescriptの設定でstrictPropertyInitializationという設定がオンになっているためである。
strictPropertyInitializationは、「undefinedの許容されてない型を初期化させる」という設定になる。
要するに変数に初期値設定しろって設定。
最初に定義したPropsはstring型であるが、何も定義されていないのでundefinedが代入される。
string型にはundefinedが許容されていないため、strictPropertyInitializationによりエラーが発生した。
2回目のPropsのように初期化すればstrictPropertyInitializationによるエラーは解決しコンパイルは可能になるが、
これは子コンポーネントでpropsを書き換えているので、今後はVue.jsがエラーを発生させた。

対策
四苦八苦した過程が残るけど自分のお勧めは4番

1.tsconfig.jsonに以下を記述しstrictPropertyInitializationの設定をオフにする

strictPropertyInitialization:false

但し全体に影響する。

2.any型やstringならばUnion型に変更しundefinedで対応できるようにする。

    @Prop() public name:string|undefined;

ただし、number型の場合はundefinedまたはnullとunion型にできないので、
この解決はできない。

    @Prop() public name:any;

anyはどの型でも機能する。但しanyになるので型の意味があまりなくなる。
stringやnumberのような複雑じゃない型の時までanyにするのは悲しい。

3.そもそも@component以下に書く

@Component(
    {
        props:{
            placeholder:String,
        }
    }
)

但しexport以下で呼び出せなくなる。

4.型宣言の際に!をつける、または?をつける
参考:https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-7.html#strict-class-initialization
参考:https://dev.classmethod.jp/server-side/typescript-assertions/

    @Prop() public name!:any;

!はコンパイラにこの型はnon-nullですよと伝える意味がある。
初期化されてないが実際には外部で変数が代入されている(丁度今回みたいな)場合に使える。
ちなみに @Prop() の中身にはoptionが設定できる。

ソースより
export interface PropOptions<T=any> {
  type?: PropType<T>;
  required?: boolean;
  default?: T | null | undefined | (() => T | null | undefined);
  validator?(value: T): boolean;
}

defaultとか設定したいときは次のような感じ

@Prop({default:"text"}) public type!:string;

ちなみに上のソースコードでも出現しているが、!の代わりに?をつけても解決する。
?は代入されてなくても構わない、という意味になる。

6.[Vue.js]vue-routerのto属性に対してparamを設定しpropを渡したい時、pathではなくnameでurlを呼び出さないといけない

<router-link
:to="{name:'hoge',params:{huga: 'hage'}}"
>

でないといけない。router.jsの方でnameで設定しないとparamsが有効にならない。
pathを設定するとurlに直接paramsを組み込まなければならない。

Laravel

1.モデルでSELECTする時にidを取得しないと、そのインスタンスにsaveもupdateもできない

大ハマり
参考:https://qiita.com/moimoinon/items/5adb4b179e3c25d189a2

悪い例
$data = Article::select('title','updated_at')->with('hashtags:name')->get();

例のようにモデルのidを取得していないインスタンスにsaveメソッドを使用して更新しようとした場合、
saveの結果としてtrueが返されてもデータベース上では更新されない。
この後の例等、予期せぬ挙動を生むことが多いので、selectする時は基本的にidは取得したほうが良い。

2.EagerLoadを使う場合、SELECTでidを取らないとwithで参照してくれない

参考:https://mseeeen.msen.jp/laravel-5-5-get-specified-column-with-with/

relationのwithも、idを軸にリレーション先のデータを取得している。
よって、もしSELECT元でidが選択されていない場合、withの参照先のデータも取得されない。

良い例
//もしidのカラムを取得していない場合はhashtagsが空になってしまう
$data = Article::select('title','updated_at','id')->with('hashtags:name')->get();

3.belongsToの場合のモデル名は単数。データ取得の際も関数でなくプロパティを通して取得。

HasManyと同じつもりで複数形にすると、参照先モデルの取得が正しくされない。

悪い例
    public function admins(){
        return $this->belongsTo(Admin::class);
    }

belongsToの参照先は1対多の1側なので、単数にしなければならない。

良い例
    public function admin(){
        return $this->belongsTo(Admin::class);
    }

リレーション先のデータを取得する際も単数形で指示する。
プロパティでアクセスできるのが大きな違い。

    //adminに対して()をつけずにプロパティでアクセスできる。
    public function scopeGetAdminName($query,$id){
        return $query->find($id)->admin->name;
    }

    //EagerLoad,withのadminが単数形になるのがhasManyの時との違い
    public function scopeWithAdmin($query){
        return $query->with('admin:id,name');
    }

その他

1,[docker] php:7.4.2-apacheのdockerイメージでドキュメントルートを変更する方法

/etc/apache2/sites-available/000-default.confのドキュメントルートを変更

000-default.conf
<VirtualHost *:80>
    # The ServerName directive sets the request scheme, hostname and port that
    # the server uses to identify itself. This is used when creating
    # redirection URLs. In the context of virtual hosts, the ServerName
    # specifies what hostname must appear in the request's Host: header to
    # match this virtual host. For the default virtual host (this file) this
    # value is not decisive as it is used as a last resort host regardless.
    # However, you must set it for any further virtual host explicitly.
    #ServerName www.example.com

    ServerAdmin webmaster@localhost
        #ここを変更
    DocumentRoot /var/www/html/
2
2
0

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
2
2