一つの記事に書く程ではないけれども、
ハマった所を今後同じ所でハマった同志のため、
また物忘れが最近酷いので再度自分がハマらないため
自分が躓いた所を備忘録集として残します。
基本的だけれども見落としやすい所が中心です。
備忘録なので書きなぐりの文章が多いです。
また間違い等があるかもしれないので、
都度修正していきます。
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
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);
}
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してもアニメーションはつかない
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 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のドキュメントルートを変更
<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/