- 投稿日:2020-09-08T22:23:15+09:00
超初心者のReact(create-react-app)基礎学習覚え書き①
Reactの最大の利点はコンポーネントの使いまわしが可能なこと!!
基礎学習をしていて思ったのは編集の際に修正点が少ない。
CSSのSass(Scss)で変数にしたような感じに近いものを感じる。
はっきり理解できとらんが、備忘録としてcreate-react-app内のディレクトリー
1.src:コンポーネントを作るJSファイル
2.public:htmlファイルや設定ファイル
3.build:本番環境用のファイル
※他のディレクトリ(node_modulesなど)は割愛実行コマンド
npm run build
srcとpublic内のファイルをバンドル(まとめて)buildディレクトリに出力npm start
ローカルサーバーを起動してReactアプリを確認できるnpm run eject
babelやwebpackの設定を変更したい時に使用Atomicデザイン
※これは余談
パーツコンポーネント単位で定義していくUIデザイン手法で、端的にはパーツの最小単位からデザインしていくこと用語
state
・コンポーネントの"状態"を指す。Reactのコンポーネント内だけで使うものを「ローカルステート」と呼ぶ
※Reduxでは「グローバルステート」
・コンポーネント内で管理する変数
・propsを使用して親→子コンポーネントに渡せるprops
コンポーネント間でデータを受け渡すためのオブジェクトコンポーネントの種類
Class Component
ClassComponent.jsximport React from 'react'; class Hoge extends Rect.component { construtor(props) { super(props); } render() { return( <div> <h2>{this.props.hoge}</h2> </div> ); } }クラスによって定義されたコンポーネント(見た目:複雑-記述量は増える)
(最近のReactではあまり使わないように記述する流れが多いらしい)
・関数ではないのでクラスとして宣言する
・React.Componentってやつを継承する
・stateってやつとライフサイクルをもつ
・propsってやつにはthisってやつが必要
・JSXはrenderメソッド内でreturnするFunctional Component
FunctionalComponent.jsximport React from 'react'; const Hoge = (props) => { return ( <div> <h2>{props.hoge}</h2> </div> ); };関数型で定義されたコンポーネント(見た目:シンプル-記述量は少ない)
・JSX(HTMLっぽい書き方のやつ)をreturnする
・ES6のアロー関数で記述
・stateってやつを持たない(stateless)
・propsってやつを引数に受け取るReact.Fragment
JSX上でコンポーネントをラップする為だけに使われる
コンソールで確認した時にhtml上で無駄に<div></div>タグが多いときにつけるタグ
省略形として、ただの<></>でも良いprops
Functional Componentでは
propsを引数に受け取り、受け取った引数をprops.hogeというように呼び出せる
Class Componentでは
1."constructor"で初期化しなければならない
2.{this.props.hoge}のように記述する必要があるpropsで受け渡せるデータ型
1.{}内に記述 ※文字列のみ{}なしでも良い
2.文字列、数値、真偽、配列、オブジェクト変数例文.title="HogeHoge" order={7} ispublished={true or false} builder={builderName}state
stateが必要なわけ
1.render内では値変更は禁止の為
2.setState()メソッドで値変更の管理をする為
3.レンダー内でのstate変更は再レンダー(無限ループ)のきっかけになる為
→だからsetStateを使いなさいよstateの設定、取得、変更
設定
・Classコンポーネントの使用が前提
・constructor()内で宣言
・オブジェクト型で記述取得
1.stateの取得は同一コンポーネント内で{this.state.hogeHoge}
で取得可能
2.子コンポーネントで参照したい場合はpropsとして渡す変更
1.関数にラップする
2.setState()内に記述されたstateのみを変更する為、他のstateに変更を与える心配はないstate例文.jsxclass Blog extends React.Component { constructor(props) { super(props); this.state = { isPublished: false } } //公開状態の反転 togglePublished = () => { this.setState({ isPublished: !this.state.isPublished }) }; render() { return ( <> <Article title={"React基礎"} isPublished={this.state.isPublished} toggle={() => this.togglePublished()}/> </> ) } } export default Hoge続きは②
- 投稿日:2020-09-08T22:16:07+09:00
今更ながら graphql-code-generator の便利さを痛感する
はじめに
今日も今日とて、フロントReact + バックRailsのSPA + APIのアプリ開発していたところ
TypeScriptのReact側で、react-apolloの型宣言がめんどくさいと思っていました。
バックエンド側はGraphQLを使用しているので、いろんなところに型宣言をしているようにも感じて、微妙。。
そこでgraphql-code-generatorを使っていろいろ気持ち悪い部分を解消していこうという話をします。
今回の構成
フロントエンド
- React(SPAで)
- TypeScript
- create-react-app
- React Apollo
バックエンド
- Ruby
- Rails(APIで)
- GraphQL
※上記2つのリポジトリはこちらのリポジトリから連動させる仕組みとしました。(開発環境として)
とりあえずApolloの公式通りにやってみる
バックエンド側に
todos
という、Todoモデルにあるデータを全て取得するAPIを作成しておきました。これをフロントエンド側で取得し、表示します。
src/App.tsx+import { gql, useQuery } from "@apollo/client"; import React from "react"; import logo from "./logo.svg"; import "./App.css"; +const TODOS_QUERY = gql` + query { + todos { + name + } + } +`; const App = () => { + const { loading, data } = useQuery(TODOS_QUERY); + return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <p> Edit <code>src/App.tsx</code> and save to reload. </p> - <a - className="App-link" - href="https://reactjs.org" - target="_blank" - rel="noopener noreferrer" - > - Learn React - </a> + {loading ? ( + <p>Loading ...</p> + ) : ( + <ul> + {data && data.todos.map(({ name }, i) => <li key={i}>{name}</li>)} + </ul> + )} </header> </div> ); }; export default App;型宣言していないので、エラーが出ましたね。
型宣言してあげます。
用意する型は、
Todo
モデルの型と、レスポンス値の型です。レスポンスは
{"data":{"todos": []}
という値が返るようにしています。interface Todo { name: string; } interface TodosData { todos: Todo[]; }
TodosData
を以下のように使います。- const { loading, data } = useQuery(TODOS_QUERY); + const { loading, data } = useQuery<TodosData>(TODOS_QUERY);エラーなく実行できました。
では、
GraphQL Code Generator
が入っていたらどうなるか試してみます。GraphQL Code Generatorを使う
公式の手順通り、インストールとセットアップ
https://graphql-code-generator.com/docs/getting-started/codegen-config
$ yarn add -D @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-operationspackage.json"scripts": { "generate": "graphql-codegen" }バックエンド側に用意しているエンドボインとは
http://localhost:5000/graphql
なので、schema
にこれを使います。codegen.ymlschema: http://localhost:5000/graphql documents: ./graphql/queries/*.graphql generates: ./src/types.d.ts: plugins: - typescript - typescript-operations※
documents
オプションを使用する場合に、@graphql-codegen/typescript-operations
が必要みたいです。
documents
に指定した場所に、todos
のクエリを記載します。graphql/queries/todos.graphqlquery { todos { name } }バックエンドを起動してある状態で、用意した
generate
コマンドを実行してみます。$ yarn generate
src/types.d.ts
ファイルが生成されました。src/types.d.ts...省略... export type Unnamed_1_QueryVariables = Exact<{ [key: string]: never; }>; export type Unnamed_1_Query = ( { __typename?: 'Query' } & { todos: Array<( { __typename?: 'Todo' } & Pick<Todo, 'name'> )> } );
Unnamed
となってしまっているので、クエリに名前をつけて再度実行します。graphql/queries/todos.graphql-query { +query todos { todos { name } }
src/types.d.ts
ファイルにTodosQuery
というType
が定義されました。これを
useQuery
の型に利用してみます。src/App.tsx+ import { TodosQuery } from "./types.d"; - const { loading, data } = useQuery<TodosData>(TODOS_QUERY); + const { loading, data } = useQuery<TodosQuery>(TODOS_QUERY);同じように動作が確認できました。
src/App.tsx
にTodo
モデルの型と、レスポンス値の型を定義しなくて良くなりました。でも、TODOデータを取得する為のクエリを
src/App.tsx
とgraphql/queries/todos.graphql
の2箇所に書いているのが気持ち悪いですよね。
todos
を取得する為の専用のuseQuery
があれば型もクエリも渡さなく済むのに。。。@graphql-codegen/typescript-react-apolloを導入する
todos
を取得する為の専用のuseQuery
があれば型もクエリも渡さなく済むのに。。。ということで、この気持ち悪いを解消していきます。
まずはインストール
$ yarn add -D @graphql-codegen/typescript-react-apollo
typescript-react-apollo
を追加します。codegen.ymlschema: http://localhost:5000/graphql documents: ./graphql/queries/*.graphql generates: ./src/types.d.ts: plugins: - typescript - typescript-operations + - typescript-react-apollo
生成コマンドを実行
$ yarn generate
src/types.d.ts
にuseTodosQuery
という関数が生成されたので使ってみます。src/App.tsx- import { TodosQuery } from "./types.d"; + import { useTodosQuery } from "./types.d"; - const { loading, data } = useQuery<TodosQuery>(TODOS_QUERY); + const { loading, data } = useTodosQuery();ちゃんと動きましたね。
GraphQLの便利なところとして、同じAPIでも、必要なフィールドのみを取得することができる特徴があります。
先ほど、
todos
のデータを取得する際、name
のみ指定し取得、一覧表示のような機能を実現しました。これを個別に、編集、削除といった機能を実現するには、
name
がユニークでない限り、id
のようなもので、
todo
を特定する必要があります。別の画面等で、
name
に加え、id
も必要な場面があった場合、以下のようなクエリを別で作成したくなってきます。query todos { todos { id name } }しかし、
graphql-code-generator
で生成する関数は全て、src/types.d.ts
に入るように設定しています。ここには既に、
name
のみを指定したtodos
を取得するクエリの関数が存在しているので、以下のようなファイルを作成し、
yarn generate
を実行すると、Not all operations have an unique name
というエラーが発生します。graphql/queries/todosIncludeId.graphqlquery todos { todos { id name } }
query
の右に記載している名前が、ユニークでないといけないってことですね。graphql/queries/todosIncludeId.graphql-query todos { +query todosIncludeId { todos { id name } }
query
の名前をユニークな名前に変更してみました。すると、
src/types.d.ts
にuseTodosQuery
とは別に、useTodosIncludeIdQuery
関数が生成されました。GraphQLの便利な特性を潰すことなく利用できますね。
参考文献
- 投稿日:2020-09-08T22:06:10+09:00
Azure Static WebApps で react URL 直打ち
routes.jsonの配置
static webapps 用のルーティング設定ファイル『routes.json』をpublicに配置して、デプロイすればOK
{ "routes": [ { "route": "/*", "serve": "/index.html", "statusCode": 200 } ] }MSのサイト
開発環境なら別にいいけど、サイトにのっけると CSR なので、index.html に来てもらわないと、href でサイトの相対パス設定しても 404 なります
- 投稿日:2020-09-08T21:02:12+09:00
ReactとTSでMaterial Designのアプリのセットアップをする手順
- アプリを作る
yarn create react-app my-app --template typescript
- Material UIを追加する
yarn add @material-ui/core
- Robotoをインストールする
yarn add fontsource-roboto
- index.tsxに
import 'fontsource-roboto';
を追加- Iconsを追加
yarn add @material-ui/icons
- 使いたいアイコンをインポート
import { AccessAlarm, ThreeDRotation } from '@material-ui/icons';
- routerをインストール
yarn add react-router-dom && yarn add @types/react-router-dom
- 投稿日:2020-09-08T20:46:30+09:00
【React.useRef】イベントリスナー内で最新のステートを参照できない時の対処法
はじめに
関数コンポーネントのイベントリスナー内で、
State(ステート/状態)
が正しく扱えない場合の対処方法です。
React.useState()
のステートを、イベントリスナーのコールバック関数内で参照しようとすると、値が最新の状態になっていないことがあります。うまくいかない例
counter
というState
を宣言- ボタンをクリックすると
counter
に+1
- クリックに反応したイベントリスナーが
func()
を発火counter
の値を出力関数コンポーネント// ① const [counter, setCounter] = React.useState(0); // ④ const func = () => { console.log(counter); }; // ③ React.useEffect(() => { window.addEventListener("click", func); }, []); // ② return ( <button onClick={() => setCounter(counter + 1)}> ボタン </button>この例では、
④ console.log(counter)
で出力される値は常に0
です。
イベントリスナーの登録時点のcounter
の値で固定されてしまい、ステートが更新されても出力は変わりません。これでは何回クリックしたかわからない...。
useRef()
を使う
React.useRef()
を使うことで、常に最新の状態を参照することができます。うまくいく例const [counter, setCounter] = React.useState(0); // 追加 const counterRef = useRef(); // refオブジェクトを作成 counterRef.current = counter; // refはcounterを参照する const func = () => { // refを出力する console.log(counterRef.current); }; // -----以下は変更なし----- React.useEffect(() => { window.addEventListener("click", func); }, []); return ( <button onClick={() => setCounter(counter + 1)}> ボタン </button>コールバック内で
counter
を使うかわりに、counterRef.current
を使用します。
このようにすることで、最新のステートを参照することができます。まとめ
関数コンポーネントのイベントリスナー内で、最新の
state
が参照できない場合は、コールバック内でState
を使うかわりに、State
を参照するRef
を使用します。このようにすることで、最新のステートを参照することができます。
- 投稿日:2020-09-08T17:03:23+09:00
Gatsby + GitHub Pages でポートフォリオページを無料でシュッと作る
エンジニアたるもの、自分のポートフォリオページは持っておきたいですよね。
Gatsby + GitHub Pages を利用したポートフォリオページ作成手順をまとめましたのでご活用ください。GitHubでポートフォリオ用リポジトリ作成
まずはポートフォリオ用のリポジトリを作成していきます。
- GitHub右上のメニューから 「New repository」をクリック
- Repository name に
<ユーザ名>.github.io
を入力し、 「Initialize this repository with a README」にチェックつけて「Create repository」をクリック
- リポジトリ作成完了。Clone with SSH をコピーしておきます
- ターミナルで作成したリポジトリをチェックアウト
# <user>を置き換えて!!! $ git clone git@github.com:<user>/<user>.github.io.git && cd <user>.github.ioGatsbyで静的サイト作成
- Gatsby CLI インストール
$ npm install -g gatsby-cli
- Gatsby Starterを使ってサイト作成
- 今回はgatsby-simplefolioを使います。
$ gatsby new gatsby-simplefolio https://github.com/cobidev/gatsby-simplefolio
- gatsby new が終わったらサイトのディレクトリへ移動
$ cd gatsby-simplefolio
- 開発環境用サーバ起動
$ gatsby develop
- http://localhost:8000/ へアクセスし、Gatsbyで作成した静的サイトを確認。早いですね。
作成した静的サイトを GitHub pages として公開
実は
<user>.github.io
の命名規則でリポジトリを作成した時点で自動的にGitHub Pagesとして公開されています。
↓こんな感じ。READMEの内容が表示されてますね。
ページのカスタマイズをする前に、先ほどGatsbyで作成したページを一旦そのままGitHub Pagesとして公開してみます。
package.json
にデプロイ用コマンド追加gatsby-simplefolio/package.json"start": "npm run develop", "serve": "gatsby serve", "clean": "gatsby clean", - "test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\" && exit 1" + "test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\" && exit 1", + "deploy": "gatsby build && cp -pvr public/* ../ && git add ../ && git commit -m 'Deploy to production' && git push" },
- デプロイコマンド実行
$ yarn run deploy
- しばらくすると GitHub Pagesに反映されます
カラーテーマ変更
サイト全体のカラーテーマを変更することができます
https://uigradients.com/ で好みの色を見つけましょう。
- 気に入ったグラディエーションのカラーコードを以下のファイルに反映すればOKです。
gatsby-simplefolio/src/style/abstracts/_variables.scss// COLORS $primary-color: #02aab0; $secondary-color: #00cdac;コンテンツ内容設定して完成!
- 中身はただのReactです。タグ定義なんかも自由にカスタマイズしていきましょう!
独自ドメインを設定
以降の手順は任意です。お金がかかるケースもあります
ドメインを取得する
- お好きなところでどうぞ
GitHub Pages サイトのカスタムドメインを管理する - GitHub Docsを参考に、DNSプロバイダでレコード作成
- ↓はAWSのR53でAレコードを設定した例
CNAME
というファイルが作成されます。設定ページからではなく手動でこのファイルを作成してもOKです。
- これで、独自ドメインでポートフォリオページを表示できるようになります!
https://mishiwata1015.com/
※スマホ対応できてないです参考
- GitHub Pages について - GitHub Docs
- Quick Start | GatsbyJS
- Starter Library | GatsbyJS
- Gatsbyにはブログ用など様々な用途のStarterがあります。こちらから検索してみるだけで面白いです
- https://docs.github.com/ja/github/working-with-github-pages/managing-a-custom-domain-for-your-github-pages-site#configuring-an-apex-domain
- 投稿日:2020-09-08T09:41:27+09:00
ドメイン駆動設計における5層アーキテクチャの全体図とソースの実装例
今回の記事では、過去に記述した以下のバックエンドに関する記事を一つに統合した内容となっている。
従来のドメイン駆動設計の4層アーキテクチャにDCIアーキテクチャを組み込んでいく過程で、様々なパラダイムが発生し、
最終的に4層アーキテクチャにミッション層を追加した5層アーキテクチャという形に落ち着いた。
今回の記事では、投稿した過去の記事の内容を5層アーキテクチャによって概念を整理し、整合性を担保している。投稿した過去の記事一覧
・ドメイン駆動設計のユースケース層(アプリケーション層)を軍事思想(作戦術)でドーピング
https://qiita.com/aLtrh3IpQEnXKN7/items/853ecb3cd109dd016476・OOUI(オブジェクト指向設計)によるバックエンド設計のパラダイムシフト
https://qiita.com/aLtrh3IpQEnXKN7/items/3aa05f9628544c43f279・DCIアーキテクチャの活用方法を紹介
https://qiita.com/aLtrh3IpQEnXKN7/items/355ad12f82ac424abea3・エリック・エヴァンスが提唱したアーキテクチャの4層モデルを拡張する
https://qiita.com/aLtrh3IpQEnXKN7/items/b7fe2014ccefcbb9e458・ドメイン駆動設計のミッション層を設計する手法を紹介
https://qiita.com/aLtrh3IpQEnXKN7/items/98e0c2d2ee0776e0e039・5層アーキテクチャモデルにおけるドメイン分析
https://qiita.com/aLtrh3IpQEnXKN7/items/e5d1a276c07f1fe140be各レイヤーの説明
レイヤーの全体図
1.コントロール層
アプリ外からアクセスの入り口となるインターフェースを主にRestApiで提供する。アプリ外からのアクセスがWeb、iOS、Androidと増加するたびにインターフェースを追加する必要がある。
インターフェース以外の機能として、コントロール層からユースケース層へデータを受け渡す際のデータ変換、コントロール層からアクセス元へのデータ変換(JSON化)を行う。データの受け渡し、データ変換機能をメインに担当する。2.ユースケース層
ビジネスロジックで実現したい目的を記載するための層。ミッション層のメソッドの呼び出しのみを行う。
ユースケース層では、フロントエンドから取得したデータを格納するためのBeanクラスを必ず用意する。
Beanクラスをミッション層へ引数として渡し、ミッション層内で具体的なロジック内容を実装する。ユースケース層のビジネスロジックは以下の種類で実装する。
偵察・・・画面に表示するデータを取得する
順次・・・ビジネスのワークフローを順番通りに進める
ゲリラ・・・不定期に行われるイベント処理を実施する
監視・・・DB内部の情報を監視し、アプリの規約に違反したユーザーの発見などを行う
エスカレーション・・・アプリのルールに違反しているユーザーへの通知、警告などを行う
エマージェンシ・・・緊急事態に対応する
相対・・・キャンセル処理などビジネスのワークフローから外れる例外処理3.ミッション層
具体的なビジネスロジックを記述するための層。ビジネスロジックはDCIアーキテクチャによって実装が行われる。
この層では、ユースケース層で実現したい目的をドメイン層のメソッドを組み合わせて実現する。
以下の観点で、ドメイン層のメソッドを組み合わせロジックを作成する。イベント・・・DBへデータを書き込む事象
リソース・・・企業が取り扱うサービス or 商品
ルール・・・イベントに紐づく運用ルール
テクノロジー・・外部ライブラリを使用して実装されるメールの転送やファイルアップロード
エージェント・・・ミッション層のロジックを統率する。イベント、リソース、テクノロジーのメソッドが全て集約する。4.ドメイン層
ミッション層のロジックを構成する層。ミッション層内でメソッドの呼び出しが行われる。
ドメイン層では、アプリ全体で共通するデータ構造の取得、共通するデータ構造に依存した業務ルールの提供、データ集約に基づいたデータ登録 or 更新 or 削除処理を取り扱う。5.インフラ層
外部ライブラリを使用したロジックを記述し、全レイヤーに外部ライブラリの機能を提供する。例としてメールの送信、ログの出力などが該当する。
ライブラリはバージョンアップや使用するライブラリ変更されるなど、頻繁に発生する箇所する。そのため、DIP(依存関係逆転の原則)に従って、
ドメイン層にインターフェースを配置し、実際のロジックはインフラ層に記述する。インターフェースをデータインジェクション(依存性注入)機能を利用してインタンス生成を行う。実装するクラス一覧
各レイヤー層に記述するクラス一覧について記載
1.コントロール層
Controller・・・REST APIの提供、Convetクラスのメソッドの呼び出し、ユースケース層の画面レベルのメソッドの呼び出し、
Web用、Andoroid、iOSへ引数を返却する際の値変換(JSON化)など
Coverter・・・REST APIから取得した画面の入力値の値をユースケース層へ引き渡す際の値の変換2.ユースケース層
Bean・・・コントロール層から取得した入力値を格納して、ユースケース層へ引き渡す際のクラス。getter setterでメソッドを構成。表示画面と1対1の関係にある。
SearchOperation・・・検索したデータを画面表示することを目的としたビジネスロジック
RegularOperation・・・ビジネスのワークフローを次状態に進めるデータ登録、更新処理を目的としたビジネスロジック
GuerrillaOperation・・・ゲリライベントで発生するデータ登録、更新、削除処理を目的としたビジネスロジック
MonitoringOperation・・・DBのデータを監視し、規約違反が発見した場合、規約違反のデータ登録、更新、削除処理を目的としたビジネスロジック
EscalationOperation・・・エスカレーションラダーを設定し、規約違反を起こしているユーザーに各エスカレーションに応じた通知処理を目的としたビジネスロジック
EmergencyOperation・・・緊急事態対応を目的としたビジネスロジック
IrregularOperation・・・従来のビジネスのワークフローから外れるデータ登録、更新、削除処理を目的としたビジネスロジック3.ミッション層
Mission ・・・Beanクラスを引数として受け取り、Beanクラスに対応したActorクラスのインスタンス、Actorクラスの型となるRoleインターフェスの選択、Roleメソッドの実行を行う。
Actor・・・Roleインターフェースを実装するクラス。Mixinを使用して多重継承を実施。
Role・・・インターフェース。ミッション層のEvent、Resource、Rule、Technologyのメソッドを集約する。ミッション層のロジックを組み合わせ ユースケース層で実現したいロジックを実装する。
Event・・・DBの登録 or 更新 or 削除に関する事象を実装するクラス。ドメイン層の、Aggregates、Servicesの組み合わせで実装される。
Resource・・・企業が取り扱う商品 or サービスのデータをDBから取得するクラス。ドメイン層の、Value Objects、Factories、Entities、Repositoriesの組み合わせで実装される。
Rule・・・運用ルールを実現するクラス。ドメイン層の、Specification、Value Objects、Factories、Entities、Repositoriesなどのメソッドの組み合わせで運用ルールを実現する。
Technology・・・技術的なビジネスロジックを実装するクラス。インフラ層のメソッドとインフラ層のメソッドを組み合わせて実現する。4.ドメイン層
Factorys・・・DTOクラスを引数とし、ValueObjectインスタンスを生成
ValueObject・・・共通構造クラス。DTOをフィールド変数として持ち、getterメソッドとisメソッドのみで構成されている。DTOのデータを加工して提供、DTOのデータに応じたif分の提供などを行う。
Specifications・・・ビジネスルール or 入力値チェックなどのビジネスロジックを提供する
Repositorys・・・DBからデータ検索処理を行うクラス。
Aggregates・・・特定のデータ範囲に応じて、データの登録、更新、削除を行うクラス。
Services・・・上記で上げたドメイン層のロジックに分類できない処理を取り扱うクラス。5.ドメイン層
Mail・・・メール送信を行う。
SFTP・・・SFTPによるデータ送受信を行う。
FileUpload・・・ファイルアップロードを行う。
- 投稿日:2020-09-08T08:33:22+09:00
【React × Firebase】おそらく世界一シンプルなログイン機能実装【サインイン・サインアウト】
はじめに
この記事では、React×Firebaseを使用して世界一シンプルにログイン機能を実装します。
デザインは全てMaterial-UIにお任せし、機能のみを追求しました。
それでは、張り切っていきましょう!環境構築
なにがともあれ、create-react-appで環境構築しましょう!
create-react-app [app-name]
そして、必要なライブラリをinstall
npm install --save-dev firebase react-router-dom @material-ui/core
では、次にFirebaseのアプリを作成します。
Firebaseと接続
まずはFirebaseにアクセスし、アプリを作成してください。
下記、手順となります。Component作成
Firebase.auth()
ユーザーを作成しよう!
ログインしよう!
最後に
- 投稿日:2020-09-08T01:53:05+09:00
Hasura, Apollo, Reactでsubscriptionsのリアルタイム更新の実装
メモ書き
需要が有れば書き直します。実装コード
httpの通信からWebSocketの通信に切り替える必要があるのでプラグインのインストール
yarn add subscriptions-transport-wsWebSocketLinkを使ってApolloClientのlinkをwsに変える
uriでhttp指定していたURIが
http://localhost:8080/v1/graphql
であった
WebSocketで双方向に通信したいのでws://localhost:8080/v1/graphql
に書き換える。この時、Hasura側では特に何もする必要はない。
index.tsximport { ApolloClient, InMemoryCache, gql } from "@apollo/client"; import { WebSocketLink } from "@apollo/client/link/ws"; import { useSubscription } from '@apollo/react-hooks' import ArticleCards from '../components/ArticleCards' const client = new ApolloClient({ // uriをlinkに変更(http通信からws通信にする) link: new WebSocketLink({ uri: 'ws://localhost:8080/v1/graphql', options: { reconnect: true, connectionParams: { headers: { // 認証系はここに書く } } } }), cache: new InMemoryCache(), }); export default function Home() { return ( <ApolloProvider client={client}> <ArticleCards></ArticleCards> </ApolloProvider> ); }記事一覧のコンポーネント(雑につくった)でリアルタイム更新
useQuery
を使っていた場合は、useSubscription
に書き換える。
gqlのコード以外は特に変わらないので説明は割愛ArticleCards.tsximport { useSubscription } from '@apollo/react-hooks' import Card from "@material-ui/core/Card"; import CardActions from "@material-ui/core/CardActions"; import CardContent from "@material-ui/core/CardContent"; import Button from "@material-ui/core/Button"; import Typography from "@material-ui/core/Typography"; import articleStyle from '../styles/ArticleCards.module.css'; import { ARTICLES_SUBSCRIPTIONS } from '../gql/articles'; interface ArticleType { id: string; text: string; } const Article = (article: ArticleType) => { return ( <Card variant="outlined" className={articleStyle.card}> <CardContent> <Typography variant="body2" component="p"> {article.text} </Typography> </CardContent> <CardActions> <Button size="small">MORE</Button> </CardActions> </Card> ); } const ArticleCards = () => { const { loading, error, data} = useSubscription(ARTICLES_SUBSCRIPTIONS); console.log(data) // ローディング中の表示 if (loading) return <p>loading</p> // エラー時の表示 if (error) return <p>{error.toString()}</p> // 成功してデータが帰ってきた時の表示 return ( <div className={articleStyle.article}> {data.articles.map((article: ArticleType) => ( <Article {...article} key={article.id}></Article> ))} </div> ); } export default ArticleCardsgqlでsubscriptionsを書く
参考までに
query
,subscription
,mutation
を書いておいた。gql/articles.tsimport gql from "graphql-tag"; export const ARTICLES_QUERY = gql` query { articles { id text } } `; export const ARTICLES_SUBSCRIPTIONS = gql` subscription ArticlesSubscriptions { articles(limit: 30, order_by: { created_at: asc }) { date id text } } `; export const ADD_ARTICLES = gql` mutation AddArticles($text: String = "", $date: date = "") { insert_articles(objects: { text: $text, date: $date }) { returning { id text date } } } `;参考記事
Hasura/GraphQL/React.js/Subscriptions
https://hasura.io/learn/graphql/react/subscriptions/1-subscription/Hasura/GraphQL/Vue.js/Subscriptions
https://hasura.io/learn/graphql/vue/subscriptions/1-subscription/WebSocketとは?
https://www.keicode.com/script/html5-websocket-1.php
- 投稿日:2020-09-08T00:49:58+09:00
gatsby入門 ブログ作ってサーバーにアップしてみる
gatsbyの作業履歴
gatsby入門 チュートリアルをこなす 0.開発環境をセットアップする
gatsby入門 チュートリアルをこなす 1. ギャツビービルディングブロックについて知る(1)
gatsby入門 チュートリアルをこなす 1. ギャツビービルディングブロックについて知る(2)
gatsby入門 チュートリアルをこなす 2. ギャツビーのスタイリングの概要
gatsby入門 チュートリアルをこなす 3. ネストされたレイアウトコンポーネントの作成
gatsby入門 チュートリアルをこなす 4. ギャツビーのデータ
gatsby入門 チュートリアルをこなす 5. ソースプラグインとクエリされたデータのレンダリング
gatsby入門 チュートリアルをこなす 6. 変圧器プラグイン※Transformer pluginsのgoogle翻訳
gatsby入門 チュートリアルをこなす 7. プログラムでデータからページを作成する
gatsby入門 チュートリアルをこなす 8. 公開するサイトの準備
今回:gatsby入門 ブログ作ってサーバーにアップしてみる基本のチュートリアルはこなした。。。
さて何しましょう?とチュートリアルを見ているとgithubにブログ用のソースが上がっているとの記載が
https://github.com/gatsbyjs/gatsby-starter-blog
とりあえずブログでも作ってみっか!
んで、netlifyとgithubを使うのが主流みたいだけど、nginxの勉強もしたいので
とりあえず自分のGCPのVM環境にアップしてみようと思います。
飽きたらGCPから移行するかな?ブログを構築
22:00作業開始 ローカルにgatsbyサイトを作成
まずは、ローカルにgatsbyサイトを作成します。
以下コマンドを好きなディレクトリで実行。そして風呂。
gatsby new 3s-laboo-blog https://github.com/gatsbyjs/gatsby-starter-blog
※3s-laboo-blogは任意です。
なんか、ダウンロードすげぇ時間かかったな。
ダウンロード後サイトを開発モードで起動しながら、ビールをプシュっと。
cd 3s-laboo-blog
gatsby develop
http://localhost:8000/
おー。。。超シンプル。
まぁ、こっからアレンジすればいいが、今回は最低限にだけとどめよう。
ビール、グビグビ。22:50 ブログをちょっとだけ修正
まず、顔が私じゃない!
content/assets/profile-pic.jpgを変更
あとアイコン
content/assets/gatsby-icon.pngを変更
確認するとアイコンだけ出ていない。
gatsby-config.jsを少しいじってみる。
リスタートされたみたい。
改行されてないな。
src/stylesディレクトリを追加
src/styles/global.cssを追加し、以下を記述src/styles/global.csshtml { background-color: #e0ffff; white-space: pre-wrap; }pre-wrapは改行コードが反映されるよ!
gatsby-browser.jsを修正gatsby-browser.js// custom typefaces import "typeface-montserrat" import "typeface-merriweather" import "prismjs/themes/prism.css" import "./src/styles/global.css"←これ追加
あと、マークダウンファイルをちょいと直して。。。
とりあえずはこんなとこでしょ!
(後でかなり修正しないとな。。。)
ビールなくなった。
とりあえずコンパイル・起動
gatsby build
gatsby serve
動確問題ない。00:00 winscpでgcpにログインし、nginxのフォルダにアップロード
nginxの配置フォルダはnginxで設定したフォルダです。
アップロードするものは、newしたディレクトリ(ここでいう3s-laboo-blog直下)にあるpublicディレクトリ内のファイル・ディレクトリ。
https://3s-laboo.com/
イエーイ!
ということでわたくし3S Labooのブログを立ち上がりました。
時刻は00:46
風呂入ってビール飲んで歯を磨いたのも含めて3時間位で作れたー今後修正していきまーす。
今回はここまで。ありがとうございました。