ryoのぼやき

技術についての学習内容のまとめです。

【Vue.js】Vueにおけるライフサイクルフックの使い分け

この記事の内容

Vue.jsには、createdmountedさらにはupdatedなど、
関数を定義できる場所が複数あり、
どこで何を書くべきなのかよく分からなくなりがちです。

これらはライフサイクルフックというもので
それぞれの使いどきは、
どんなタイミングで実行したいのかによって決まります。

そのため、これらを理解するには、
Vueインスタンスが生成されてから破棄されるまでの流れ、
つまり、(名前の通り)「ライフサイクル」を理解することが最初の一歩につながります。

そんなわけで、Vueインスタンスのライフサイクルについて調べてことを書きたいと思います

インスタンスの生成、初期化

まずは、new Vue()によって、Vueインスタンスが生成されます。
生成された後は、初期化処理を行います。
この初期化処理の過程で、「リアクティブデータの初期化」が行われます。
この初期化が行われると、
dataの更新が画面の表示と同期されるようになるわけです。

そして、この「リアクティブデータの初期化」の前後に行われるフックが
それぞれあります。

まず、初期化の前に行われるフックが、beforeCreateです。
この段階では、dataなどのデータが初期化されていないので、
読み込もうとしてもundefinedとなります。

そして、初期化の後に行われるフックが、createdです。
この段階には、リアクティブデータの初期化が住んでいるので、
dataを読み込むことができます。

<フックの使いどころ例>
beforeCreate
パッと使いどころが思い浮かばなかったのですが、 公式ドキュメントでは、循環参照をするコンポーネント群は
コンポーネント登録をする時に、無限ループに陥るので、
片方のコンポーネントがもう一方をコンポーネント
初期登録するまで待つような処理をする必要があり、
そのような処理をする際には、beforeCreateで行うようです。

created
ここでは、APIを呼んでサーバなどからの
データ取得処理を書くことが多いです。
他には、DOMへのマウントが完了して
画面が描画されるまでのローディングの表示処理も
ここで書いたりします。

マウント

このフェーズでは、コンポーネントがDOMにマウントされます。
つまり、VueインスタンスとDOMが紐付けされます。

具体的な流れとしては、
まず、Vueインスタンスelオプションが指定されているかが確認されます。
されている場合は、そのまま次のフェーズに移りますが、
このオプションが指定されていない場合は、mount関数が実行されたタイミングで、
次のフェーズに移ります。

その後はtemplateオプションを持っているかが確認されます。
持っている場合は、templateがrender関数にコンパイルされます。
持っていない場合は、elオプションで定義されたDOMをtemplateとして、
コンパイルします。

そして、ようやくマウントが行われます。
つまりインスタンスのelement(vm.$el)を作成し、elオプションに置換します。

ここで、このマウントの前に実行されるフックがbeforeMountです。
また、マウントの後に実行されるフックはmountedです。(これはよく使いますよね)

<フックの使いどころ例>
beforeMount
ここに関しても、実際の使用ケースは浮かばなかったのですが、
使いどころとしては、Vueのelementに置き換わる前のelement要素に
アクセスする処理はここに書くことになるかと思います。

例えば、以下のようなDOMがあったとします。

<div id="sample" data-hoge="hello"></div>

このDOMに対して、次のVueインスタンスをマウントすると、
このようになります。

new Vue({
  el: '#sample',
  template: '<div>Hello</div>',
  beforeMount(){
    console.log(this.$el) //<div id="sample" data-hoge="hello"></div>
    console.log(this.$el.dataset.hoge)//hello マウント前のelement要素にアクセス
  },
  mounted(){
    console.log(this.$el) // <div>Hello</div>
  }
})


mounted
上の説明と重複しますが、
mountedはマウント後に実行されるので、
templateにアクセスすることができます。

用途例としては、templateへの初期処理や、
ローディングの非表示処理などが挙げられるかと思います。

データの変更 / 画面の更新

いわゆる、画面が表示されている状態です。
このフェーズにおいては、
データが変更されると、render関数が実行され再描画が行われます。

この再描画の前後でそれぞれ、
beforeUpdateupdatedのフックが実行されます。

<フックの使いどころ例>
beforeUpdate
再描画前のDOMからの要素の取得処理などは、
ここで書きます。

Updated
そして、再描画したDOMに対しての初期処理などは、
ここで書きます。

インスタンスの破棄

インスタンスはv-if、v-forや、vue-routerなどで描画がされなくなるタイミングで、
破棄されます。
他にも、Vueインスタンスdestroy関数を実行しても破棄されます。

この破棄のタイミングの前後で実行されるフックが、
beforeDestroydestroyedです。

<フックの使いどころ例>
beforeDestroy
ここで書く処理として挙げられるのは、
Vueインスタンスの要素に別のインスタンスを紐付けたりした場合です。
紐付けしたインスタンスの破棄の処理をbeforeDestoryで行います。

destroyed
ここはインスタンスの破棄後に行う
TearDownの処理を書くことが多いです。

まとめ

Vueインスタンスのライフサイクルの概要を理解しておくと、
他のVueAPIの動きについて調べた時の理解を深めるのに役立つと思います。

正直、まだいくつかのフックについては、使いどきが掴めていないのもありますが、
今のうちに概要を掴めてよかったです。

【参考】
Vue インスタンス — Vue.js https://jp.vuejs.org/v2/guide/instance.html#%E3%82%A4%E3%83%B3%E3%82%B9%E3%82%BF%E3%83%B3%E3%82%B9%E3%83%A9%E3%82%A4%E3%83%95%E3%82%B5%E3%82%A4%E3%82%AF%E3%83%AB%E3%83%95%E3%83%83%E3%82%AF

vuejs2 - When to use the lifecycle method beforeMount in vue.js? - Stack Overflow

【Vue.js】slotについて(スコープ付きslot、propとの使い分けetc)

この記事の内容

Vue.jsにはslot(スロット)という仕組みがあり、 その中にさらに、スコープ付きスロットという仕組みがあります。 これが、理解しづらく感じる人が多いと思うので、 僕なりの理解を説明します。

はじめに slotとは

  • slotとは、Vue.jsのテンプレート(<template>)で使えるタグの1つです。
  • ざっくりとした言い方をすると親コンポーネントから、子コンポーネントに描画内容を直接渡すことができるタグです。
  • コンポーネントから渡した描画内容を、子コンポーネントに直接表示することができます。
  • propsは基本的に値を渡すのに対して、slotでは描画内容を渡します。

    用途

    コンポーネントでは、描画内容を決定できないときに使います。
    コンポーネントとして、
    「この部分に、こういう役割のものを表示したい。
    けれど、どのように表示するかは、このコンポーネントを使う側で決めてほしい」

    という時です。

    例えば、スマートデバイスのヘッダーを考えてみてください。

右上にボタンを置くことは、モバイルアプリでもよくあると思います。
Twitterだと、このような感じですね。

f:id:greko_prg:20200211192714p:plain

f:id:greko_prg:20200211192711p:plain


Twitterの場合もそうですが、画面によってこの右上のボタンって見た目や用途が変わりますよね

例として、この右上のボタンを1つのコンポーネントとして実装するとこうなるかと思います。

<template>
  <div v-if="currentScreen === 'home' ">
    <star-button/>
  </div>
  <div v-else-if="currentScreen === 'search' ">
    <setting-btn/>
  </div>
</template>


これだと、右上のボタンで表示する内容が増えるたびに、
分岐が増えてしまいます。

なので、この右上の領域に何をどのように表示するかは、
使う側の親コンポーネントに全て任せたいという考えになります。

それを実現するのがslotというわけです。
右上の領域をslotとして解放しておくことで、
コンポーネントを使う側に描画内容を自由に決めてもらうことができます。

slotの使い方

以下にVue.js公式ドキュメントの例を載せます。

コンポーネントで子コンポーネントを使用(値を渡す側)

<navigation-link url="/profile">
  Your Profile
</navigation-link>


コンポーネントの定義(値を受け取る側)

<!-- navigationLink.vueのテンプレート -->
<a
  v-bind:href="url"
  class="nav-link"
>
  <slot></slot>
</a>


最終的に下のように描画されます。

<a
  v-bind:href="url"
  class="nav-link"
>
  Your Profile
</a>


複数のスロットを使いたいときは、名前付きスロットを使用します。
コンポーネント("my-component"とします)

<div>
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot name="main"></slot>
  </main>
</div>


コンポーネント

<my-component>
  <template v-slot:header>
    <h1>Here is Header part</h1>
  </template>
  <template v-slot:main>
    <p>Here is Main part</p>
  </template>
</my-component>


コンポーネントタグのname属性で指定した箇所に対し、
コンポーネント<template>タグのv-slotで対応するコンテンツが入ります。

slotを使うメリット

  • slotを使うことで描画内容を親コンポーネントで決定することができます。)

→上でも触れましたが、例えばpropsを使う場合は、描画内容は子コンポーネントで決めることなります。
そして、propsによって、描画内容を切り替える処理を書かなくてはいけず、
描画内容が増えるたびに、子コンポーネントが肥大してしまいます。
そもそも汎用的なコンポーネントは、ビジネスロジックを持つべきではありません。
汎用的ではなくなってしまいますので。

どんなコンポーネントが「汎用的コンポーネント」かに関しては、
アトミックデザインでいう、Organisms(有機体)以下のコンポーネント{Atoms(原子),Molecules(分子),Organisms(有機体)}は
「汎用的コンポーネント」に該当すると言っていいと思います。(個人的見解だし、ケースバイケースです)
[参考]

Atomic DesignとCSS設計 - Atomic Designとは何か | CodeGrid



スコープ付きslotについて

しかし、子コンポーネントにアクセスがしたい状況というのは往々にしてあるので、子コンポーネントが許容したデータに限り、親コンポーネントからアクセスすることが可能です。このアクセス可能なデータはスロットプロパティと呼ばれます。
分かりづらい部分なので、ここでも例をもとに見ていきたいと思います。

まず、親コンポーネント側です。

<current-user>
  <template v-slot:default="slotProps">
    {{ slotProps.user.firstName }}
  </template>
</current-user>


* v-slotとして指定したslotPropsを通して、子コンポーネントにアクセスすることができます。
コンポーネント側も見てみます。

<span>
  <slot v-bind:user="user">
    {{ user.lastName }}
  </slot>
</span>


* 親コンポーネントにアクセスを許容するデータをv-bind:user:"user"の部分で指定しています。 * このバインドしたuserというデータ(スロットプロパティ)に対して、親コンポーネントではslotProps.userとしてアクセスできるわけです。
なので、上記の例は、次のように展開されます。

<current-user>
  <span>
    {{ user.firstName }}
  </span>
</current-user>

Vuetifyにおけるslot

Vue.jsのコンポーネントフレームワークであるVuetifyをよく使うのですが、
Vuetifyの公式ドキュメントの各コンポーネントページには、SLOTSという項目があります。

f:id:greko_prg:20191130193822p:plain
画像は、v-text-fieldコンポーネントの例

以前まで、これが何を意味しているのかよく分かっていなかったのですが、
つまり、このコンポーネントを使う場合に、親コンポーネントからアクセスが可能なデータがここに示されているという訳でした。

追記

別の例を交えて説明した記事をこちらに書いたので、
まだよく分からない方は見てみてください。
【Vue.js】スコープ付きスロットが理解できるように例を交えて考える - Qiita

まとめ

Vue.jsは直感的に理解しやすいものが多いのですが、slotはそれらと比べると直感的とは言えないかもしれません。
そういった理由から、Slotを理解することが、Vue中級者への一歩と言われているようです。
Atomicデザインに基づいたきれいなコンポーネントを設計する上では、slotの理解が必須だということが分かったので、見て見ぬ振りせずきちんと向き合っていきたいと思いました。

[参考]

スロット — Vue.js

Vue.js: slots vs. props - Nico Meyer - Medium

【書評】【IA/UXプラクティス】IA/UXについて

こんばんわ。

最近、UI/UX関係の仕事があり、
先輩から、おすすめの本を貸していただいたので、
週末の夜の時間を利用して読んでみました。

読んだのは、この本です。
「IA/UXプラクティス」

坂本貴史さんという、UXデザイナーの方が著者です。

ページ数は、200ページほどで、
読むのにかかった時間は、だいたい1時間30分くらいでした。
割とざっと読んで部分もあるので、しっかり読んだら、3時間くらいかかるかもしれないです。


まずこの本の構成ですは、
1.UXデザインについて
2.モバイルでのUXデザイン
3.モバイルUXのデザインのパターン
4.デザイン設計をどう行っていくか
5.カスタマージャーニーマップについて
↑こんな感じでした。
実際の目次は、少し違いますが、要約するとこんな感じです。

では、それぞれの章ごとの要約と感想を書いてみたいと思います。

1. UXデザインについて

最初は、「UXとは」を説明している章でした。
UXとは、IAとは、ユーザビリティとは、と言った内容に加えて、
HCD(Human Centered Design)というサービス設計手法の紹介がありました。
HCDを説明する上で、似た概念である「アジャイル」や、「リーン」にも触れています。
この章は、いわゆる本における導入の章なので、そんな深い印象はなかったです。。
ただ、どんな開発プロセス(HCD,アジャイル,リーンetc)でも、
「計測可能な"評価"のプロセスを行う仕組みが必要」と書かれていたのは興味深かったです。
開発プロセスの上辺をなぞって、やりっぱなしにならないようにってことでした。

一応、HCDについても書いておきます。
HCDでは、以下のプロセスを経ることで、ユーザの満足度を継続的に向上させる手法です。
/「利用状況の理解と明確化(Measuring)」
→「ユーザや組織の要求事項の明確化(Learning)」
→「デザインによる解決案の作成(Creating)」
→「評価(Testing)」/
→「利用状況の理解と明確化(Measuring)」→...

HCD_POCCES

(参考)https://www.dalberg.com/what-human-centered-design

2.モバイルでのUXデザイン

この章は、モバイルのインターフェースを設計する上で、
考慮すべきことが多く説明されていました。
PCとの違いや、レスポンシブデザインについてとかですね。
モバイルOSごとに、推奨のコンポーネントサイズがあることとかは、
あんまり意識したことがなかったので、勉強になりました。
とはいえ、こう言った内容は、脳みそにこういう事柄があるというインデックスを作っておけば、
詳細は忘れててもいいと思ってるんで、「おーw」って感じで軽く流し読みしました。
ここらへんの知識が必要になったらまた読めばいいので。。

3.モバイルUXのデザインのパターン

この章も、モバイルのUXについてでした。
前の章との違いは、一般的なモバイルサイトやアプリの
ページ構成のパターンわけして、それぞれのメリット、デメリットをあげている点です。

階層構造のパターンや、タブで切り替えるようなパターンとか、それぞれの使い所が整理してあったので、
ためになる章だと思います。
ただ、これも、覚えることではないので、「へーw」って感じで流し読みです。

4.デザイン設計をどう行っていくか

この章は、前章までと次の章の橋渡し的な章でした。
前章までで説明していたデザインの原則を使って、
どのようにコンテンツを設計していくかといった話から、
プロトタイプや、シナリオなどを使って、
プロジェクトをどう進めていくのかといった話に移っていきます。
そんな感じなんで、この章も「ほーw」って感じで流していきました。


5.カスタマージャーニーマップについて

最後のこの章は、シナリオやカスタマージャーニーマップを使って、
どうやって、ユーザの要求を整理、分析していくかの手法が書かれています。
この章は、けっこう大事なことが書かれていました。。
細かいところを覚える必要ないとは思いますが、
こういうような手法を取り入れていくなら、
しっかり理解していなくてはいけない事柄が書かれています。
これらの手法って、流行りに乗って上辺をなぞって取り入れても、
効果出ないですからね。
ユーザの要求分析は、サービスを開発する上で、一番土台になる部分なので、
ここを適当にやってしまうと、「流行りに乗った、結果ゴミができた」なんていう
悲しい思いをすることになってしまいます。








はい、こんな感じの、読書記録でした。

全体の感想としては、
新しいWebサービス、アプリとかを開発する人は、
読んでおくと、きっと役に立つ本だと思います。
僕自身、ざっと流し読みしたくらいですが、
1章、5章はある程度、理解しながら読んで、
それ以外は、適宜必要なときに読む。でいいと思います?

では。

python初心者が30分で文法を覚えて競プロを始める〜その2〜

こんにちは

前回の記事では、pythonで競プロを解いていくために、
必要最低限の基本文法だけ確認していきました。

greko-engineer.hateblo.jp

今回は、前回覚えた文法を引っさげて、
AtCoderの過去問を解いていきたいと思います。

対象の問題はこれ。

atcoder.jp

問題

N個の足場があります。足場には、1,2,...,Nと番号が振られています。
各i(1<i<N)について、足場iの高さはhiです。
最初、足場1にカエルがいます。
カエルは次の行動を何回か繰り返し、
足場Nまでたどり着こうとしています。
・足場iにいるとき、足場i+1または、i+2へジャンプする。
このとき、ジャンプ先の足場をjとすると、コスト|hi-hj|を支払う。
カエルが足場Nに辿り着くまでに支払うコストの
総和の最小値を求めてください。



DP(動的計画法)と言われるパターンで解ける問題のようです。

動的計画法は↓を参考になんとなく理解しました。(とてもわかりやすかったです)
動的計画法超入門! Educational DP Contest の A ~ E 問題の解説と類題集 - Qiita



何度か失敗を繰り返して、 最終的に解答はこのようになりました。

N = int(input())
h = [int(i) for i in input().split()]

dp = [0]*N
dp[0],dp[1] = 0,abs(h[1]-h[0])

for i in range(2,N):
    dp[i] = min(dp[i-2] + abs(h[i]-h[i-2]), dp[i-1] + abs(h[i]-h[i-1]))
 
print(dp[N-1])

とてもシンプルな解答になりました。

ちなみに同じ問題をJavaで書いた時はこうなりました。

import java.util.*;
 
public class Main {
    static final int INF = Integer.MAX_VALUE;
    public static void main(String[] args) {
        
        try(Scanner scan = new Scanner(System.in)){
            int N = Integer.parseInt(scan.next());
            int[] h = new int[N];
            int[] d = new int[N];
            
            for(int i=0;i<N;i++) {
                h[i] = Integer.parseInt(scan.next());
                d[i] = INF;
            }
            d[0]= 0;
            d[1]= Math.abs(h[1] - h[0]);
            
            for(int i = 2; i<N; i++) {
                
                int prepre = d[i-2] + Math.abs(h[i]-h[i-2]);
                int pre = d[i-1] + Math.abs(h[i]-h[i-1]);
              
                d[i] = Math.min(prepre, pre);  
            }
            System.out.println(d[N-1]);
                
        }
    }
 
}

やっぱりpythonは簡潔でいいですね。

そしてこの問題を通して、
↓のような文法を新しく学べました。
・まとめての変数宣言
・リスト内包表記





まず、「まとめての変数宣言」が、 ↓この部分です。

dp[0],dp[1] = 0,abs(h[1]-h[0])

カンマで区切ることで、
1行に変数の宣言をまとめて書けるみたいです。 便利ですね。




そして、「リスト内包表記」。 ↓この部分ですね。

h = [int(i) for i in input().split()]



やってる処理としては、
input()で受け付けた複数文字の標準入力を、
split()で1つ1つの文字に分割されたlistに変換し、
そのリストの各要素iに対し、int(i)でintに変換して、
それを配列にするといった感じです。(わかりづらくてすいません。。)

基本的には、 [iの処理 for i in 配列など]と書くみたいです。 i に対して行う処理をfor文の外側に出したような書き方ですね。



まだ簡単な内容しか学べてないですが、
競プロでアルゴリズムを学びながら、 並行して、新しい言語を学べていけるのはとても有意義でした。

同じ境遇の人にはぜひ進めたいです。

python初心者が30分で文法を覚えて競プロを始める〜その1〜

こんにちは

 

最近、競技プログラミングに興味を持ち始めて、
AtCoderという競技プログラミングのサイトで過去問を解いてみました。

しかし、解けない問題がほとんどでした。

atcoder.jp

 
僕は一番詳しく知ってるJavaでチャレンジしたのですが、

自分がJavaで30行くらい書いた問題がpythonだと3行で解かれているのを見て衝撃を受けました。


そして、これを機にpythonで競プロを進めていくことにしました。
 

というわけで、まずは基本的な文法のPythonでの書き方を調べてみました。
・変数宣言
・出力
・if文
・for文




まずは変数宣言。

a = 1

え、型定義いらないんですか
??
そのシンプルさに驚きを隠せません。
a=1と書くだけで感動させてくれます。






次は出力。

print(a)

シンプルです。
System.out.print()って書くのがバカバカしくなりそうです。




どんどんいきます。
次は、if文。

if a > 2:
    print("a>2")

インデントするだけでいいみたいです。
{}←これ、打つの苦手だからありがたいです。




そしてfor文。

for i in range(10):
    # 0,1,2,3,4,5,6,7,8,9が出力される
    print(i)

これは見慣れなくて??ってなりました。


for i in range(n)だとiが0から(n-1)まで繰り返すみたいです。
今回は、使えればOKのスタンスでいくので深い理解はあきらめます。
あと、しれっと上の例に入ってますが、
コメントは#(シャープ)で書くみたいです。





とりあえず、超基本的な文法はこれくらいでしょうか。
これだけ頭に入れておいて、
細かい部分はコード書きながら調べるスタイルで行こうと思います。

次回は、実際にpythonatcoderの過去問を解いてみたいと思います。