観賞魚のWikiを自作する日記シリーズ 〜ESLintやPrettierの設定など〜
はじめに
現状ESLintもPrettierも設定できておらず、快適な開発環境とは言えない。 なのでこれから設定していく。
eslint + prettier
ここ読む解決やったー
いつのまにかeslint-plugin-prettierが推奨されないものになってた | K note
webpackでまとめたい
webpack類を導入し、設定ファイルを書く。
何を導入している下記になるかたはリポジトリのpackage.jsonにあるdevDependenciesなどを見てください。
以下が設定ファイル
aquariumpedia-front/webpack.config.ts at master · kotarou1192/aquariumpedia-front · GitHub
> yarn start
これでwebpack-dev-serverが立ち上がるようになっている。
さいごに
今日はここまで、疲れました。
続く。
観賞魚のWikiを自作する日記シリーズ 〜Reactの準備とメニューバーの作成〜
はじめに
今日はReact+TypeScriptの環境構築とメニューバーの作成まで行こうと思う。
今後使うRailsのWebAPI(アカウント作成)
既に適当に作っているのでRailsでのWebAPI作成の記録は割愛。
現在以下のような仕様のAPIがある。
POST http://localhost:3000/api/v1/users
リクエストに必要なパラメーター
- name
- 30文字まで
- 英数字とハイフンのみ使える。
- email
- 255文字まで
- password
- 6-50文字
example
{ "name": "takashi", "email": "takashi@example.com", "password": "hogefugapiyo" }
レスポンス
SUCCESS http response 200 ok
メールがメアドに送られる。
{ "message": "activation mail has been sent" }
FAILED http response 400 bad request
エラーの配列が返ってくる
[ { "messages": [ "has already been taken" ], "key": "name" }, { "messages": [ "has already been taken" ], "key": "email" } ]
まずは後数回の記事でこのAPIを使うフロントを作ろうと思う。
Reactの準備
> create-react-app aquariumpedia-front --template typescript
以上のコマンドでtypescript+Reactなプロジェクトを作成した。
とりあえず動かしてみる
> yarn start
動いた。
生成されたファイルを確認してみる。
Reactはそこまで詳しくないのでわからないのだが、とりあえずはこれで良さそうである。動いているからヨシ!Webpackとか何も入ってないけどいまのところはヨシ!
src配下を全部消して、とりあえず動くものを作っていこうと思う。
今回はなうでヤングなアローファンクションとHOOKSを使ってコンポーネントを作っていく。
最初の一歩
とりあえずいつもの通りにエントリーポイントを作っていく。
index.tsx
import React from 'react'; import ReactDOM from 'react-dom'; import { App } from './App'; ReactDOM.render(<App></App>, document.getElementById("root"));
index.htmlにはrootというIDのついたDOMがあるので、そこにAppというコンポーネントを表示する。
つぎにApp.tsxと言うファイルを作り、そこに最初の単純なコンポーネントを作っていく。
App.tsx
import React from "react"; export const App: React.FC<{}> = () => { return <div>hello, world</div>; }
表示できたかな・・・?
無事にハローワールドしている。
DOMの中身もOK。
拡張していこう。
メニューバーのコンポーネント
かっこいいメニューバーを作っていこうと思う。
イメージとしてはこうだ
雑さには目を瞑って欲しい。伝わればいいのだ。
真ん中に検索、右側に鉛筆マークとアカウントマーク、左にロゴ。
アカウントマークにマウスオーバーするとウィンドウが出てきてログインか新規登録を選ばせるようにしたい。
ログイン後はマイページを司る。
鉛筆マークは投稿ボタンだ。
とりあえずcomponentsと言うフォルダを作り、その中にMenuBar.tsxと言うファイルを作る。
その中身を編集し、とりあえず表示したいものを並べてみる。
MenuBar.tsx
import React from "react"; export const MenuBar: React.FC = () => { return ( <div> <div>logo</div> <div>search</div> <div>account</div> <div>write</div> </div> ); }
とりあえず縦に並んだ。横にして色をつけてあげよう。
色々と変なところはあるが、とりあえずはモックとしてはこれでいいだろう。
ボタンを画像などに差し替えてあげればそれらしくなりそうだ。
今日の作業をGitに保存しておく。
> git add -A > git commit -m"add: menu bar mock"
我ながら雑なコミットだが許して欲しい。
masterブランチに直接コミットしている時点で神の怒りを買う恐れがあるので、次からはトピックブランチを切っていく。
また、ESLintやPrittierなどの設定もどうなっているかわからないので、次回で設定してしまいたい。
いちおうGitHubへプッシュしておいた。
GitHub - kotarou1192/aquariumpedia-front
今日はここまで。続く。
観賞魚のWikiを自作する日記シリーズ 〜要件定義〜
はじめに
先日作るとは思い立ったものの、どう言う機能が必要か、どう言ったページがあるといいかがいまだにふわっとしている。
勢いでアカウント部分だけ適当に作ったものの、それで本当にいいのかもわからない。
そこで、今日は要件定義について考えてみようと思う。
今回作るものの概要
今回作るものは多人数編集型の飼育方法が載った観賞魚の図鑑である。
図鑑の形式はmarkdown。
荒らし対策のために編集にはログインを必要とし、できればバージョンも管理したい。(編集履歴を残す)
一番上に写真が何枚かあって、その下に本文、一番下に記事へのコメントがあるといいなと思っている。
こんな具合の2種の魚がいたとして、その魚のデータには
みたいにタグとして情報を持たせる。
タグはユーザーが自由に追加できるものとする。
大まかにはこのようなところだろうか。
これをできるだけミニマムに作っていって、後で少しずつリッチにしていく方針で行こうと思う。
必要な機能
- アカウント登録
- ログイン
- ログアウト
- 退会
- deleted_userになるが、作成・編集した図鑑は当たり前ながら残る。書いたコメントは消える。
- 同じメアドで再登録ができる。
- 図鑑投稿
- 図鑑検索
- tagと魚名での検索。
- 新着図鑑の表示
- 図鑑へコメント
- 図鑑の編集
- ユーザーの書いた図鑑・編集した図鑑の一覧をユーザーのページに表示
ミニマムに行くとこの辺に絞られるのじゃないだろうか。
APIの仕様
- jsonを返し、成功時はステータスに200、失敗時は一律400を返す。
失敗時はjsonにエラーキーとして単語とメッセージ(例えば投稿失敗なら{ error_key: title, message: too short } )を入れ、なぜ失敗したかをフロントに伝達する。
RestfulっぽいAPIにしたいので、post, put, get, deleteを使い分ける。新規作成-post
- 編集-put
- 表示-get
- 削除-delete
一つのAPIごとにGitHubのWikiにドキュメントとして使い方を残していく(できれば)。
ページのデザイン(おおまか)
必要なページ
- top
- 図鑑ページ
- userページ
上にバー的なものを作る。
バーにはログイン/ログアウトぼたん、アカウント作成ボタン、アカウント設定ボタン、記事投稿ボタン、ロゴ を置く。
左に新着記事やカテゴリを置いたサイドバーを設置する。
以上が大まかな設計図である。
早速作っていこうと思う(続く)
観賞魚のwikiを自作する日記シリーズ
先日観賞魚のWikiがあったら面白いのではないかとふと思いつき、それを実行に移し出したのでメモ。 このプロジェクトは一人で暇な時にコツコツ作っていく予定。
使うもの
- RubyOnRails
- TypeScript
- React
- PostgreSQL
現在出来ていること
- aws lightsailにサーバーを借りる
- https://aquariumpedia.org/ の取得
- Let'sEncriptにてSSL証明書の自動取得
- nginxの大まかな設定
- react dom router のためのnginxの設定
- https://aquariumpedia.org/fishes/freashwater/kingyo こう言ったURLでも一つのbundle.jsを参照し続ける。
- ローカルでのaccount作成機能のAPI構築(アカウント作成、メール送信、アカウント有効化、全ての(有効化されていないのも含む)アカウント表示 のみ)
これからやるべきこと
出来たらいいな
- capistranoでのAPIサーバーのデプロイ
- circleciを使ってのCI/CD環境
これが現状です。 他にもやることがあるので完成するかはわかりませんが、勉強用にできる限り一人で作ってみたいと思います。
続く
ReactチュートリアルをTypeScriptで書き下す
こんばんは、たかしです。
身内で勉強会をやっているのですが、そこでTypeScriptでReactを書こうという話になりました。
そこでReactチュートリアルをTypescriptで書き下してウォーミングアップをしようという話になったのですが、これがなかなか面倒くさそうだったのでここにまとめたいと思います。
どなたかの参考になれば嬉しいです。
環境構築は飛ばして早速本編に入っていきます。
データをprops経由で渡す
そもそもpropsってなんぞやということで調べました。
propsとは
function Welcome(props) { return <h1>Hello, {props.name}</h1>; }
一言で表すならば上の通りです。 つまり、propsというオブジェクトを渡しているということですね。 これは次と等価だそうです。
class Welcome extends React.Component { render() { return <h1>Hello, {this.props.name}</h1>; } }
しかしこれをTypeScriptで表そうとなると一つ問題があります。
propsの型がなんなのか分からない問題
話をReactチュートリアルに戻して、renderSquare関数でSquareコンポーネントのpropsのプロパティにvalueを定義し、そこに数字を渡して数字の書いてあるボタンを表示する部分があります。
こちらです。
これをそのままタイプスクリプトでやろうとすると次のようなエラーが出るはずです。
Property 'value' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<Square> & Readonly<{}> & Readonly<{ children?: ReactNode; }>'.
プロパティ「value」は型「intrinsicAttributes」と「IntrinsicClassAttributes
つまり型が問題みたいです。
以下の方法で解決しました。
まず、propsの型を定義してあげます。
interface SquareProps { value: number; }
次にこの作った型をクラス呼び出し時に適用されるようにしてあげます。
class Square extends React.Component<SquareProps> { render() { return ( <button className="square"> {this.props.value} </button> ); } }
ちなみにReact.Componentの受け取る型はこうです。
class React.Component<P = {}, S = {}, SS = any>
PはPropsのことだと思われます。上のコードでこのPに型が与えられました。
SはStateのことだと思われます。Stateとは、コンポーネントごとに持っている状態のようなものだそうです。
今回はまだ使っていないので定義しないでおきます。
以上の編集で実際に動作確認してみます。
動きました、ヨシ!
では次に進みましょう。
インタラクティブなコンポーネントを作る
詳細はこちらです。
チュートリアル:React の導入 – React
この章でついにStateをつかうのですが、ここでまた問題発生です。
素直に書いていると下のようなエラーが出るはずです。
Property 'value' does not exist on type 'Readonly<{}>'
今回も素直にこうしてあげましょう。
interface SquareState { value: string; }
lass Square extends React.Component<SquareProps, SquareState> { constructor(props: SquareProps) { super(props); this.state = { value: "", }; } render() { return ( <button className="square" onClick={() => { this.setState({ value: "X" }); }} > {this.state.value} </button> ); } }
これで動きます。
この後に関しては難しいところがなさそうなので書くかは謎です。
RDBにおける正規化(第一正規化)
第一正規化
1つのマスには1つのデータのみを置くこと。
ひとつのマス(ここでは便宜上そう呼びます)に1つの値が入っている場合、その値はスカラ値と呼ばれるそうです。
正しくない例
記事ID | 記事タイトル | タグ |
---|---|---|
A001 | 初めまして | |
A002 | 沖縄旅行 | 日記 旅行 買い物 |
A003 | 食事を作りました | 日記 料理 |
この例ではタグというカラムに値が0~3つ入っています、アウト。
このようなことはRDBの第一正規化においては許されることではありません。
しかし、その通りにすると、この例でいうタグは記事に対して一つずつしか許されないことになってしまいます。
なぜ許されないのか?
マスにいくつか数字が入ってる(つまり配列等になっている)ばあい、主キーを選ぶとレコードの各マスの値を一意に決定できなくなってしまうからです。
これはRDBとしてはあるまじきことで、RDBにおいてはすべての正規化において、Aを決めるとBが一意に値が定まるという大事なルールがあります。(Aは例えば主キーや何らかの組み合わせ、Bはその戻り値)
戻り値は一つでなければなりません、配列が返ってくるとどれが目当てのデータなのかもわかりません。
しかし、実際のところ上の例のようなデータの構造を扱いたい場合があります。
どうすれば許されるのでしょうか?許される方法を考えてみましょう
方法その1、なんか沢山カラムを増やしまくる
記事ID | 記事タイトル | タグ1 | タグ2 | タグ3 |
---|---|---|---|---|
A001 | 初めまして | |||
A002 | 沖縄旅行 | 日記 | 旅行 | 買い物 |
A003 | 食事を作りました | 日記 | 料理 |
なんか色々あほっぽいですが一応実現は出来ます。
でも、見るからに問題が多そうです、例えば現状タグ上限3つまでとか。
他の方法を考えましょう。
方法その2、タグの数だけレコードを増やしてみる
記事ID | 記事タイトル | タグ |
---|---|---|
A001 | 初めまして | |
A002 | 沖縄旅行 | 日記 |
A002 | 沖縄旅行 | 旅行 |
A002 | 沖縄旅行 | 買い物 |
A003 | 食事を作りました | 日記 |
A003 | 食事を作りました | 料理 |
この方法で達成したか?と思うのですが、まだです。主キーが決められない問題が発生します。
主キーを無理やり決める場合、記事ID、記事タイトル、タグの3カラムすべて指定することが必要になりますが、そうするとA001のようにタグを持たない記事は残念ながら主キーにNULLは含めないのでアウトです。
では空マスに「タグ無し」を入れるという方法ではどうか?というとそれもマズいです。
なぜか?
そもそもタグって日記と分けて考えるほうが自然ではありませんか?
だって日記は1つずつ、タグはそれにいくつかくっつく。でもタグ自体はその日記固有のものではなく、同じものが他の日記にもくっついたりしています。
たとえるならば、会社に勤めている人がいたとして、その人は会社の一部だ!と言っているようなものです。家に帰ると家の一部だと言われます。それってもはや人という存在が別にあると考えたほうが、当たり前ですが、分かりやすくないですか?
つまりタグと日記は別々の存在であるはずです。
つまりこれではいまいちテーブルの意味が分かりづらく、レコード一つ一つが何なのかもピンときません。これではタグが主体なのか日記が主体なのか…そもそも何が主体とか言ってる時点でおかしな話なのです。1つの存在について語っているわけですから。
別の方法を考えましょう。
方法その3、テーブルを分ける
テーブル1つしか使ってはいけないなんて誰が言った!
そうです、テーブルをいくつか使えばいいんです。
記事テーブル
記事ID | 記事タイトル |
---|---|
A001 | 初めまして |
A002 | 沖縄旅行 |
A003 | 食事を作りました |
タグテーブル
記事ID | タグ |
---|---|
A002 | 日記 |
A002 | 旅行 |
A002 | 買い物 |
A003 | 日記 |
A003 | 料理 |
これで、上の問題は解決しました。 あとは様々なアプローチでこのテーブルを利用するだけです。
学んだこと 計算量オーダー
ここに答えがありました。
全く関係ない記事ですがメモ用↓
値渡しと参照渡しの違いを理解する
またもやわかりやすい記事様です、それを自分用に改悪まとめます。間違ってたらごめんなさい。
そもそもlog(n)ってなんやねん
- 25とかでの5を求めるということ。
log2 8 の値を求めよ。とかいわれたら、2を何乗すると8になるかを求めよ、ということ。このとき2を底という。
以上復習です。
では記事に戻って、例えば1~32までの数字に対して5を見つけようという2分探索をするとして、
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32
この32個の数からとりあえず16と比べて(1)
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16
さらに8と比べて(2)
1,2,3,4,5,6,7,8
さらに4と比べて(3)
5,6,7,8
さらに半分して6と比べてどっちに含まれてるか調べて(4)
5,6
さらに半分してry(5)
5
やった!5が見つかりました。
これで、2分割の5乗で計算量は5ステップ (log(n)) となりました。
log_2 32は5なのでlog(n)のnはたぶん32のことです。32個データがあるということなので。
より一般に「n が毎ステップごとに定数分の1になる」場合の繰り返し回数は O(logn) になります。
とのこと。
というか、上の参考元の記事の二つにすべてが載っています。知識0で読んでも???なので読む前の事前知識として考えていただけたら。
以上改悪でした。数学もう忘れててボロボロなのでほんとに高校の参考書でも買わないといけません。
何度も言いますが、間違ってる可能性大なので間違ってたら教えてください。