20210414のReactに関する記事は11件です。

ちょっとしたReactでのアニメーション

ちょっとしたReactでのアニメーション ※この記事は、ガッツリすごいアニメーションをやるものでは、ありません! TypeScriptでReactなどWebフロントを実装している際、ちょっとした変化を持たせたいなと思って書きました。 ちょっとした変化 文字の色を変えたい 変位をゆっくりしたい 見た目の変化 HTML、CSSは、インターネットが始まって成長してきた言語です。 非常に簡単に書くことができる。 なので、色んな人が、様々な技巧でWebサイトを面白く、美しく見せてきました。 React、Vue などフレームワークが変わっても土台は、変わっていません。 React で実装してみよう 細かいことは、置いといてどうやるのか? import React, { useState } from "react"; import { css } from "emotion"; // css in js export function Animation() { const [isFlag, setFlag] = useState(true); const color = isFlag ? "red" : "blue"; const size = isFlag ? "100px" : "300px"; const textcolor = isFlag ? "Black" : "White"; const animation_style = css({ width: size, backgroundColor: color, transition: "1s", color: textcolor, }); return ( <div className={animation_style}> <p>test</p> <button onClick={() => setFlag(!isFlag)}>Change</button> </div> ); } 上記のコードで、実行するとボタンを押すとサイズが変化する。その変化は、1秒で行われます。 transition この要素は、変化にかかる時間を指定しています。 CSS in JSでは、変数を組み込むことができるので、 CSSに変数を組み込んでboolなどで要素の状態を制御しています。 あとがき この書き方は、一般的なのかどうかは、知りません。 自分の考える動きを起こせるアニメーションのライブラリを探す過程で、よく先人のCSSの実装を説明しているサイトに行きます。 自分の環境で実現できるのであれば、こういった書き方で、ちょっとしたものは、実現して探す時間を他の作業に当てようと思いました。 参考ページ
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

意外と単純ではない TextBox が atom である理由

はじめに Dwango でニコニコ生放送のフロント開発を担当している @misuken です。 前回の記事 普遍的な atom と molecule の境界を意識したコンポーネント設計 では、 内包する構成要素が無ければ意味を成さないコンポーネントかどうか を焦点にすることで、 atom と molecule を普遍的に、どのプロジェクトでも共通した粒度として扱えるようになることを紹介しました。 今回はその記事の最後で挙げていた TextBox SelectBox ComboBox のもっと奥深い粒度の話を掘り下げていきたいと思います。 TextBox の粒度も単純ではない <input type="text" /> を出力するような TextBox というコンポーネントを作った場合、ほぼ 100% の人が atom として認識するでしょう。 しかし、ただのテキストボックスと言えどもそれより小さい粒度の物が存在しないとは言えません。 例えば Google の検索フォームの入力欄を見てみましょう。 右端のボタン二つは入力欄とは別に置かれているボタンであると言えるのですが、入力をクリアするボタンは、関心の対象や責務の境界から捉えても、テキストボックスに標準搭載された機能と言えないでしょうか? テキストボックスのクリアボタン テキストボックスのクリアボタンは、なぜテキストボックス標準搭載の機能と言えるのか。それは、以下のような理由からです。 クリアボタンの責務が完全にテキストボックス内で完結している 完全に閉じた責務であり、コンポーネント外で制御する必要がない コンポーネントを使用する側としてはクリアボタン制御が隠蔽されていてほしい テキストボックスの入力状況とボタンの表示が密接に関係している 空のときは非表示で、入力されると表示される テキストボックスを設置する全ての場所で要求される可能性がある クリアボタンがこれだけテキストボックスと密接な関係にあり、テキストボックスが無ければクリアボタンの存在意義がないとなれば、標準搭載されていないと毎回要求された場所に実装するのは明らかに面倒です。 これを裏付けるように Edge では <input type="text" /> に標準でクリアボタンが付いていたりします。 全てのブラウザで標準搭載されていないクリアボタン Edge では標準搭載されているテキストボックスのクリアボタンですが、残念ながら全てのブラウザで標準搭載されているわけではありません。 そうなると、検索フォームを作る際「入力欄にテキストを入力したら出現するクリアボタンを付けてください」という要求が来たとき、自力で実装する必要が出てきます。 すると、ただの atom だと思っていたコンポーネントでクリアボタンも出力する必要が出てきます。 <input type="text" class="text-box" /><button class="clear-button" /> ここで 内包する構成要素が無ければ意味を成さないコンポーネントかどうか という知見を持ち合わせていないと、「あれ、原子だったはずが、さらに分解できる要素が出てきて分子っぽくなったぞ、 atom と molecule どっちが正しいんだろう?」と迷うことになってしまいます。 知見を持ち合わせていれば、クリアボタンはオプションであって、それが無くても主体であるテキストボックスの意味を成していることから、明確に atom と断言できるわけです。 意外とリッチなテキストボックス クリアボタンは標準搭載されていないブラウザが多いのですが、 type 属性を変えると、ブラウザに実装されている様々な要素が現れます。(実装されているかはブラウザによります) 数値 <input type="number" /> スピンボタンが表示されます。 日付 <input type="date" /> 日付ピッカーが表示されます。 属性は粒度に影響を与えない 属性を変えただけでコンポーネントの粒度が変わってしまっては、それこそ収拾がつかなくなってしまうので、テキストボックスはどんなリッチな補助機能が付いたとしても TextBox を主体としている以上 atom であり続けるべきです。(あくまで TextBox の表現の違いでしかないため) TextBox という役割が atom であると捉えれば、これ以上分割できないことがわかります。 自作コンポーネントとの整合性 テキストボックスであれば、 <input type="text" /> を使って実装するのが当たり前ではありますが、 <input type="number" /> のスピンボタンのスタイルが気に入らないなど、ブラウザ標準では対応できないこともあるでしょう。 大抵は CSS で変更可能なように疑似要素が用意されているのですが、それでも対応できない場合もあります。 そのような場合は、同等の機能をコンポーネントとして自作するしかありません。 このような場合も、クリアボタンのときと同様に、 <input type="number" /> に対してボタン要素などを追加する必要が出てきます。 もし、単純に要素の数だけでコンポーネントの粒度を切り替えていたとしたら、 <input type="number" /> は atom だけど、自作スピンボタンを追加したほうのコンポーネントは molecule というように、全く同じ表示で全く同じ機能を有していながら粒度が違うことになってしまいます。 このように物理的な視点で粒度を捉えてしまうと、適切な粒度管理が行えなくなってしまうことがわかります。 粒度を物理で捉えない 粒度というと物理的な印象を受けますが、要素を物理的に捉えて粒度とすると破綻します。 これが粒度設計でハマりやすいポイントになっていのかもしれません。 BCD Design で言うところの Base つまり UI の型名で粒度を捉えられれば、普遍的な粒度を手に入れることが可能です。 そのため、コンポーネント名の末尾に安定して洗練された UI の型名を付けることが、コンポーネントの像をより明確にし、粒度が明確になることで依存関係も明確になるなど、様々な曖昧さを排除するメリットに繋がります。 このように、一切の主観を含まず正規化された結果は普遍であるため、プロジェクトを横断しても利用可能な長期的な資産となります。 さらに奥深い粒度の話 まだ SelectBox と ComboBox の話を書いていませんが、長くなったので今回はここまでにしておきます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

react context template

import React, { FC, Dispatch, SetStateAction, createContext, useState } from "react"; interface Data { foo: string; } type SetData = Dispatch<SetStateAction<Data>>; export const DataContext = createContext<Data>({ foo: "" }); export const SetDataContext = createContext<SetData>(() => Promise.resolve()); interface Props { bar: number; } export const Provider: FC<Props> = ({ children }) => { const [data, setData] = useState<Data>({ foo: "" }); return ( <DataContext.Provider value={data}> <SetDataContext.Provider value={setData}>{children}</SetDataContext.Provider> </DataContext.Provider> ); };
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Redux Toolkit[環境構築]

Redux・TypeScript作成方法 $ npx create-react-app アプリ名 --template redux-typescript Git Hubはこちらから VScodeにESLint+Prettier追加します。 設定が反映されている方はしなくて大丈夫です。 この記事を参考に作成していきます。 eslint $ yarn add -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin prettier $ yarn add -D prettier eslint-config-prettier アプリの直下に.eslintrc.json作成 .eslintrc.json { "extends": [ "eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier", "prettier/@typescript-eslint" ], "plugins": ["@typescript-eslint"], "parser": "@typescript-eslint/parser", "parserOptions": { "sourceType": "module" }, "env": { "browser": true, "node": true, "es6": true }, "rules": { "適当なルール なければ書かなくてもいいです。" } } settings.jsonに追記する (command + ,)で設定が開いて右上のファイルマークを押すと settings.json変更できます。記述がなければ変更してください。 settings.json { "editor.formatOnSave": true, "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.codeActionsOnSave": { "source.fixAll.eslint": true }, } 作成アプリに必要なものインストール $ yarn add node-sass $ yarn add react-hook-form $ yarn add @material-ui/core $ yarn add @material-ui/icons これで環境構築は完成です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

はじめてのWebpack設定 本番用 開発用

はじめに ポートフォリオを作成に辺り、webpack設定の学習も兼ねて初学者がポートフォリオに組み込んでみました。 今回は、組み込んだ内容を中心に解説していきます。 バージョンはwebpack4.44.2を使用しました。 ポートフォリオ解説記事こちらです。 webpackとは webpackとは、複数のJSファイルを一つのモジュールバンドラ(ファイル)にまとめることを指します。 JSファイルだけでなく、CSSや画像ファイルもモジュールバンドラにまとめることが出来ます。 用途・メリット 用途  ・BabelでJavaScriptをトランスパイルできる  ・CSSのコンパイル  ・画像圧縮  などなど、プラグインを使用することでパフォーマンスの最適化に繋がる。 メリット  色々な参考記事をみて、僕の主観的なメリットとしては  ・ファイルサイズが少ないことで、通信量や保守性が上がる。  ・ライブラリの依存関係を解決して出力してくれる。  ・不要なコードや無駄のファイルを圧縮して、ファイルサイズを軽くする。 reactやvueなどのフレームワークを使用していると、コンポーネント毎のファイルが増えると思います。そのファイル数を、一まとめにし以上の用途やメリットがあげられるかと思います。 使用する上で、気をつけたこと。。 今回は、本番用と開発用をwebpack-mergeで分けて作業しました。 また、作業する上で以下のインストールしたものを使用しました。 インストールしたもの webpack v4.44.2 webpack-cli v3.3.12   ∟webpackコマンドでwebpackを使用するため webpack-dev-server v3.11.0   ∟ブラウザに表示し、ファイルの変更を監視 weboack-merge v5.7.3   ∟開発用と本番用に分けることができる clean-webpack-plugin v3.0.0   ∟不要なファイルを削除 html-webpack-plugin v4.5.0   ∟自動でバンドルされたファイルをhtmlに読み込む(開発途中で変更された時に、自動でかえてくれる) image-webpack-plugin v6.0.0   ∟画像を圧縮 tester-webpack-plugin v4.2.3   ∟console.logを本番用のバンドル時に削除 file-loader v6.1.1   ∟画像(jpg,pngなど)を出力 style-loader v1.3.0   ∟CSSを出力 css-loader v4.3.0   ∟CSSをcommonJSに変換 ts-loader v7.0.5   ∟TypeScriptをトランスコンパイル、また静的コード分析・ES2015以降の構文に変換 ディレクトの構成 簡単なディレクトリの構成が以下になります。 ┣━ /build ┃ ┣━ /images ┃ ┣━ /js ┃ ┃ ┗━ bundle.js ┃ ┗━ index.html ┣━ /public ┃ ┗━ index.html ┣━ /src ┃ ┣━ index.html ┃ ┗━ index.tsx ------エントリーポイント ┃ ┣━ package.json ┣━ package-lock.json ┣━ webpack.common.js ┣━ webpack.dev.js ┗━ webpack.prov.js package.jsonのscripts管理 --config webpack.[dev or prod].jsを指定する。また、webpack-dev-serverを使用する際は、webpack-dev-serverを書き込む package.json "scripts": { "start": "webpack-dev-server --config webpack.dev.js", "test": "jest", "build": "webpack --config webpack.prod.js" }, 共通設定 webpack.common.js 本番用と開発用に共通するファイルをwebpack.common.jsとして作成します。 webpack.common.js const path = require("path"); const HtmlWebpackPlugin = require("html-webpack-plugin"); const { CleanWebpackPlugin } = require("clean-webpack-plugin"); module.exports = () => { return { entry: { bundle: "./src/index.tsx", //エントリーポイント }, output: { path: path.resolve(__dirname, "build"), // バンドルファイルの指定 filename: "js/[name].js", // nameはentryで指定したファイル名を作成 }, resolve: { extensions: [".ts", ".js", ".tsx", ".jsx"], // コンパイルする言語指定 }, module: { rules: [ test: /\.css$/i, use: [ // cssを出力するローダー "style-loader", // css をcommonJSに変換するローダー "css-loader", ], }, { test: /\.tsx?$/, loader: "ts-loader", // TSでトランスコンパイル include: path.resolve(__dirname, "src"), exclude: /node_module/, }, { test: /\.(jpg|png)$/, // 画像(jpg or png)を出力するローダー use: [ { loader: "file-loader", options: { name: "[name].[contenthash].[ext]", outputPath: "images", publicPath: "/images", }, }, "image-webpack-loader", //画像を圧縮 ], }, ], }, devtool: "source-map", plugins: [ new HtmlWebpackPlugin({ template: "./src/index.html" }), new CleanWebpackPlugin(), ], //パフォーマンスヒントの表示方法を構成する performance: { hints: false }, // 250kBを超えるアセットなので、perfomaneceを追加 }; }; 開発用 development 共通設定webpack.common.jsを使用ため、webpack-mergeを読み込む。 開発用なので、modeはdevelopmentを指定。 webpack.dev.js const { merge } = require("webpack-merge"); const common = require("./webpack.common.js"); const path = require("path"); module.exports = merge(common(), { mode: "development", // webpack-dev-serverの設定 devServer: { open: true, // ブラウザに表示するためtrueへ contentBase: path.resolve(__dirname, "public"), // publicディレクトリのサーバーを開く port: "9000", // サーバーのポート番号 historyApiFallback: true,// 存在しないパスをリクエストされた場合に、404を返さずにファイルを戻す }, devtool: "cheap-module-eval-source-map", // ビルドの速度とデバックの品質を保つ }); devtoolのソースマップについては、様々な設定があり種類毎にビルドの速度やデバックに品質が異なります。 今回は無難に、cheap-module-eval-source-mapを使用しました! ちなみに公式サイトはこちらです。 本番用 production 本番用なので、modeはpriductionを指定。 webpack.prod.js const { merge } = require("webpack-merge"); const common = require("./webpack.common.js"); const TerserPlugin = require("terser-webpack-plugin"); module.exports = merge(common(), { mode: "production", //terser-webpack-pluginの設定 optimization: { minimizer: [ new TerserPlugin({ extractComments: false, //falseでライセンスコメントを抽出し削除。 trueだと抽出したファイルを生成する terserOptions: { compress: { drop_console: true, //trueでconsole.logの削除 }, }, }), ], }, }); 参考記事 技術記事https://zenn.dev/nozomi_iida/articles/a4c75f79b754e9 公式https://webpack.js.org/ 感想 今回、ポートフォリオを作成する中で一から開発環境を作成することに意識し、webpackの重要性と役割を勉強しながらポートフォリオに組み込みました。開発における品質を高めてくれることを実感しましたし共同開発時にとても役立つと思いました。次はwebpack v5に挑戦してみたいです!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

はじめてのWebpack設定 本番用 開発用

はじめに ポートフォリオを作成に辺り、webpack設定の学習も兼ねて初学者がポートフォリオに組み込んでみました。 今回は、組み込んだ内容を中心に解説していきます。 バージョンはwebpack4.44.2を使用しました。 ポートフォリオ解説記事こちらです。 webpackとは webpackとは、複数のJSファイルを一つのモジュールバンドラ(ファイル)にまとめることを指します。 JSファイルだけでなく、CSSや画像ファイルもモジュールバンドラにまとめることが出来ます。 用途・メリット 用途  ・BabelでJavaScriptをトランスパイルできる  ・CSSのコンパイル  ・画像圧縮  などなど、プラグインを使用することでパフォーマンスの最適化に繋がる。 メリット  色々な参考記事をみて、僕の主観的なメリットとしては  ・ファイルサイズが少ないことで、通信量や保守性が上がる。  ・ライブラリの依存関係を解決して出力してくれる。  ・不要なコードや無駄のファイルを圧縮して、ファイルサイズを軽くする。 reactやvueなどのフレームワークを使用していると、コンポーネント毎のファイルが増えると思います。そのファイル数を、一まとめにし以上の用途やメリットがあげられるかと思います。 使用する上で気をつけたこと。。 今回は、本番用と開発用をwebpack-mergeで分けて作業しました。 また、作業する上で以下のインストールしたものを使用しました。 インストールしたもの webpack v4.44.2 webpack-cli v3.3.12   ∟webpackコマンドでwebpackを使用するため webpack-dev-server v3.11.0   ∟ブラウザに表示し、ファイルの変更を監視 weboack-merge v5.7.3   ∟開発用と本番用に分けることができる clean-webpack-plugin v3.0.0   ∟不要なファイルを削除 html-webpack-plugin v4.5.0   ∟自動でバンドルされたファイルをhtmlに読み込む(開発途中で変更された時に、自動でかえてくれる) image-webpack-plugin v6.0.0   ∟画像を圧縮 tester-webpack-plugin v4.2.3   ∟console.logを本番用のバンドル時に削除 file-loader v6.1.1   ∟画像(jpg,pngなど)を出力 style-loader v1.3.0   ∟CSSを出力 css-loader v4.3.0   ∟CSSをcommonJSに変換 ts-loader v7.0.5   ∟TypeScriptをトランスコンパイル、また静的コード分析・ES2015以降の構文に変換 ディレクトの構成 簡単なディレクトリの構成が以下になります。 ┣━ /build ┃ ┣━ /images ┃ ┣━ /js ┃ ┃ ┗━ bundle.js ┃ ┗━ index.html ┣━ /public ┃ ┗━ index.html ┣━ /src ┃ ┣━ index.html ┃ ┗━ index.tsx ------エントリーポイント ┃ ┣━ package.json ┣━ package-lock.json ┣━ webpack.common.js ┣━ webpack.dev.js ┗━ webpack.prov.js package.jsonのscripts管理 --config webpack.[dev or prod].jsを指定する。また、webpack-dev-serverを使用する際は、webpack-dev-serverを書き込む package.json "scripts": { "start": "webpack-dev-server --config webpack.dev.js", "test": "jest", "build": "webpack --config webpack.prod.js" }, 共通設定 webpack.common.js 本番用と開発用に共通するファイルをwebpack.common.jsとして作成します。 webpack.common.js const path = require("path"); const HtmlWebpackPlugin = require("html-webpack-plugin"); const { CleanWebpackPlugin } = require("clean-webpack-plugin"); module.exports = () => { return { entry: { bundle: "./src/index.tsx", //エントリーポイント }, output: { path: path.resolve(__dirname, "build"), // バンドルファイルの指定 filename: "js/[name].js", // nameはentryで指定したファイル名を作成 }, resolve: { extensions: [".ts", ".js", ".tsx", ".jsx"], // コンパイルする言語指定 }, module: { rules: [ test: /\.css$/i, use: [ // cssを出力するローダー "style-loader", // css をcommonJSに変換するローダー "css-loader", ], }, { test: /\.tsx?$/, loader: "ts-loader", // TSでトランスコンパイル include: path.resolve(__dirname, "src"), exclude: /node_module/, }, { test: /\.(jpg|png)$/, // 画像(jpg or png)を出力するローダー use: [ { loader: "file-loader", options: { name: "[name].[contenthash].[ext]", outputPath: "images", publicPath: "/images", }, }, "image-webpack-loader", //画像を圧縮 ], }, ], }, devtool: "source-map", plugins: [ new HtmlWebpackPlugin({ template: "./src/index.html" }), new CleanWebpackPlugin(), ], //パフォーマンスヒントの表示方法を構成する performance: { hints: false }, // 250kBを超えるアセットなので、perfomaneceを追加 }; }; 開発用 development 共通設定webpack.common.jsを使用ため、webpack-mergeを読み込む。 開発用なので、modeはdevelopmentを指定。 webpack.dev.js const { merge } = require("webpack-merge"); const common = require("./webpack.common.js"); const path = require("path"); module.exports = merge(common(), { mode: "development", // webpack-dev-serverの設定 devServer: { open: true, // ブラウザに表示するためtrueへ contentBase: path.resolve(__dirname, "public"), // publicディレクトリのサーバーを開く port: "9000", // サーバーのポート番号 historyApiFallback: true,// 存在しないパスをリクエストされた場合に、404を返さずにファイルを戻す }, devtool: "cheap-module-eval-source-map", // ビルドの速度とデバックの品質を保つ }); devtoolのソースマップについては、様々な設定があり種類毎にビルドの速度やデバックに品質が異なります。 今回は無難に、cheap-module-eval-source-mapを使用しました! ちなみに公式サイトはこちらです。 本番用 production 本番用なので、modeはpriductionを指定。 webpack.prod.js const { merge } = require("webpack-merge"); const common = require("./webpack.common.js"); const TerserPlugin = require("terser-webpack-plugin"); module.exports = merge(common(), { mode: "production", //terser-webpack-pluginの設定 optimization: { minimizer: [ new TerserPlugin({ extractComments: false, //falseでライセンスコメントを抽出し削除。 trueだと抽出したファイルを生成する terserOptions: { compress: { drop_console: true, //trueでconsole.logの削除 }, }, }), ], }, }); 参考記事 技術記事https://zenn.dev/nozomi_iida/articles/a4c75f79b754e9 公式https://webpack.js.org/ 感想 今回、ポートフォリオを作成する中で一から開発環境を作成することに意識し、webpackの重要性と役割を勉強しながらポートフォリオに組み込みました。開発における品質を高めてくれることを実感しましたし共同開発時にとても役立つと思いました。次はwebpack v5に挑戦してみたいです!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

React入門

目次 React入門 - Part1 - VsCodeをインストールしてReactでHello World React入門 - Part2 - Next.jsを使ってページ遷移を行う React入門 - Part3 - コンポーネントを書いてみる React入門 - Part4.1 - 親子間コンポーネントへの値の受け渡し - props編 React入門 - Part4.2 - 親子間コンポーネントへの値の受け渡し - useContext編 React入門 - Part4.3 - 親子間コンポーネントへの値の受け渡し - Redux編 React入門 - Part5 - jsonファイルの読み込み、表示 React入門 - Part6 - apiの呼び出し、値の受け取り(axios等) React入門 - Part7 - mockサーバを利用してみる React入門 - Part8 - hooksについて React入門 - Tips1 - JSXとは React入門 - Tips2 - スプレッド演算子 React入門 - Tips3 - dockerでReact環境を構築してみる React入門 - Tips4 - レンダリングと無限レンダリングについて React入門 - Tips5 - hooksがあればreduxは不要? このようなラインナップでやりたいと思っています。 (が、随時状況に応じ変更します。。。) 2021/04/15現在Part1,2しか出来ていません。 概要 細かいところは置いといて、Part1~Xまでサクサクっと進めることができ、React+Typescriptやその他フレームワーク、ライブラリの雰囲気をつかんでもらうことを念頭に記事を書いています。 React, next.js, axios, typescript, redux等を紹介できれいいなと思っています。 一通りやれば、何となく全体を触ったような感じになるかと思います。 というか、それを目指します。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

React/redux/chart.jsのメモ

npx create-react-app sample --template redux-typescript cd sample npm install axios npm install --save react-chartjs-2 chart.js npm start src/features/covid19/data.json [ { "totalConfirmed": 557, "mainlandChina": 548, "otherLocations": 9, "deltaConfirmed": 0, "totalRecovered": 0, "confirmed": { "total": 557, "china": 548, "outsideChina": 9 }, "deltaConfirmedDetail": { "total": 0, "china": 0, "outsideChina": 0 }, "deaths": { "total": 17, "china": 17, "outsideChina": 0 }, "recovered": { "total": 0, "china": 0, "outsideChina": 0 }, "active": 0, "deltaRecovered": 0, "incidentRate": 0.4510818002025252, "peopleTested": 0, "reportDate": "2020-01-22" } ] src/features/covid19/covid19Slice.ts import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'; import axios from 'axios'; import { RootState } from '../../app/store'; import datajson from './data.json' const apiUrl = 'https://covid19.mathdro.id/api/daily'; type APIDATA = typeof datajson; export type Covid19State = { data: APIDATA; }; const initialState: Covid19State = { data: [ { "totalConfirmed": 557, "mainlandChina": 548, "otherLocations": 9, "deltaConfirmed": 0, "totalRecovered": 0, "confirmed": { "total": 557, "china": 548, "outsideChina": 9 }, "deltaConfirmedDetail": { "total": 0, "china": 0, "outsideChina": 0 }, "deaths": { "total": 17, "china": 17, "outsideChina": 0 }, "recovered": { "total": 0, "china": 0, "outsideChina": 0 }, "active": 0, "deltaRecovered": 0, "incidentRate": 0.4510818002025252, "peopleTested": 0, "reportDate": "2020-01-22" }, ], }; export const fetchAsyncGet = createAsyncThunk("covid19/get", async() => { const {data} = await axios.get<APIDATA>(apiUrl); return data; }) const covid19Slice = createSlice({ name: 'covid19', initialState: initialState, reducers: {}, extraReducers: (builder) => { builder.addCase(fetchAsyncGet.fulfilled, (state, action) => { return { ...state, data: action.payload, }; }); }, }); export const selectCovid19 = (state: RootState) => state.covid19.data; export default covid19Slice.reducer; src/app/store.ts import { configureStore, ThunkAction, Action } from '@reduxjs/toolkit'; import counterReducer from '../features/counter/counterSlice'; import covid19Reducer from '../features/covid19/covid19Slice'; export const store = configureStore({ reducer: { counter: counterReducer, covid19: covid19Reducer, }, }); export type AppDispatch = typeof store.dispatch; export type RootState = ReturnType<typeof store.getState>; export type AppThunk<ReturnType = void> = ThunkAction< ReturnType, RootState, unknown, Action<string> >; src/features/covid19/LinePlot.tsx import React, { useEffect } from 'react' import { Line } from 'react-chartjs-2' import { useSelector, useDispatch } from 'react-redux' import { selectCovid19, fetchAsyncGet } from './covid19Slice' const LinePlot = () => { const covid19Data = useSelector(selectCovid19) const dispatch = useDispatch() useEffect(() => { dispatch(fetchAsyncGet()) }, [dispatch]) const data = { labels: covid19Data.map(({reportDate}) => reportDate), datasets: [ { data: covid19Data.map((data) => data.confirmed.total), label: 'confirmed', borderColor: 'red', fill: true, }, ] } return ( <div> <Line data={data} /> </div> ) } export default LinePlot src/App.tsx import React from 'react'; import logo from './logo.svg'; import { Counter } from './features/counter/Counter'; import './App.css'; import LinePlot from './features/covid19/LinePlot'; function App() { return ( <div className="App"> <LinePlot /> </div> ); } export default App;
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

React/FastAPI初心者が1日でaxiosで通信する(1週間だけ頑張る Day4of9)

はじめに 1週間N(E)ETになった社会人の学習記録です。 今日はReactのサンプルを写経し、使い方を覚えます。 前々回作ったFastAPIに対して、CRUDできることを目標にしましたが、できませんでした。 私のHTML/CSSのレベルは、「阿部 寛のホームページ1をかろうじて理解できる。」程度です。 正直、見た目とかどうでもいいので、CSS何それおいしいのって思っています。 ただ、複数カラムに対する絞り込み選択をアクセス並みの便利さにしようとすると、ページ遷移があると厳しそうなので、Ajax(もはや死語?)的な動作が必要なためReactを選んでみました。 私のjavascriptのレベルは、「hello world2」程度です。 取り敢えずReactのチュートリアル3は金曜日(Day0of9)にやってみました。 開発環境の設定 vimのアップデート .tsxのファイルを開いてもsyntaxがつかなかったので、Ubuntu On WSLのvimをversionを8.2に上げた。 sudo su apt install software-properties-common apt update add-apt-repository ppa:jonathonf/vim apt upgrade sudo suはお行儀が悪いので良い子は使わないこと。 開発環境をWSLからWindows側に変更 vimで編集すると、tsxのautoindentがものすごく微妙なので、VS Codeにしよう。 volumesのsourceをWindows系のパス(C:...)に変更(結局WSL系のパス(/mnt/c/...)に戻した。) 環境変数に「CHOKIDAR_USEPOLLING: 'true'」を追加4(ソースの変更に追随して再Compileをする設定。Ubuntuの場合だと設定しなくてもできる時もあった。) 実装 参考ページ とりあえず以下のページが(githubのリンクもあり)わかりやすそうだけど、そもそもReactの使い方は全くわからん。 FastAPIとの通信 参考ページを見るとAPIとの通信はReactだけではなく、Axiosというやつを使っているぽい。 とりま「react api 通信」でググるとトップ7/8がAxiosだったので、これにする。 CORS(Cross-Origin Resource Sharing)5の許可 FastAPIにReactからの通信を許可する設定を追加6 7。 main.py origins = [ "http://localhost:3000" ] app.add_middleware( CORSMiddleware, allow_origins=origins, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) axiosの設定 サンプルコピペ。 App.tsx get axios() { const axiosBase = require('axios'); return axiosBase.create({ baseURL: "http://localhost:8000", headers: { 'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest' }, responseType: 'json' }); } ネットワークのまとめ(かなり怪しい初心者なりの理解) Dockerの中だけで完結する場合は、services名(今回はdb, api, web)で通信できる。そのため、api->dbへの接続はFastAPIの「db.py」において、「HOST='db'」としている。 一方、Reactの「App.tsx」内の通信はブラウザが行っており、データの流れは後者だと考えられる。そのため、FastAPIの「main.py」において、「origins=["http://localhost:3000"]」とし、axios内のbaseURLは「"http://localhost:8000"」とする。 ブラウザ(localhost) ← localhost:3000=web ← api ← db web=localhost:3000 → ブラウザ(localhost) ← localhost:8000=api ← db 「App.tsx」内で環境変数をとってくる「process.env.ENV_VALUE」はブラウザ側の環境変数をとってくるみたい。「docker-compose.yml」で環境変数を設定して、main.pyで「os.environ['WEB_URL']」、「App.tsx」で「baseURL: process.env.API_URL」として、環境設定を押し込めたかったけど無理だった。Reactでserver側の環境変数を参照できる方法があったら知りたい。(といいつつ、サーバーの設定を外に出すのは微妙な気がするので、m4マクロみたいに上書きされる仕様になりそうだけども。) Index(一覧) とりま、参考サイトから、一覧表示に必要そうなところだけコピペ。 「@material-ui/data-grid」は一意のidがいるというエラーが出たので、FastAPI側のSchema(UserSelect)にidを追加。 とりあえず一覧はできたので、CRUDは明日頑張る。 所感 ホットリロードの有効化(CHOKIDAR_USEPOLLING=true)とCORSの許可にかなり手間取った。 こういう知ってたら一瞬だけど、知らないと調べようもなくて時間がとられるやつは、学習とはそういうものだと思って楽しむしかない。愚者は経験からしか学べない。 まあ、printfデバッグの方法8すらわからない状況から始めたことを思えば頑張ったと思う。 明日こそはReactからCRUDするぞ。 免責事項(言い訳) 上記の技術については初心者なので、あてにしないように!!! http://abehiroshi.la.coocan.jp/ ↩ https://github.com/tagawa0525/prac/tree/main/type_script/hello ↩ https://ja.reactjs.org/tutorial/tutorial.html ↩ https://qiita.com/galnele/items/b25962e9e287eb9a2146 ↩ http://www.tohoho-web.com/ex/cors.html ↩ https://qiita.com/whitphx/items/9278f948520c8d5b7b5a ↩ https://fastapi.tiangolo.com/ja/tutorial/cors/ ↩ https://qiita.com/mtanabe/items/49a116354c2ad9603942 ↩
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

React+FastAPI+dockerでWeb開発のお勉強 (dockerコマンド不使用縛りプレイ)

はじめに 仕事の進みが悪すぎて現実逃避したくなったので、気になっていたReactをさわってみることにしました。 4月ということで、新入社員や、学生の方でも作業しやすいようにGUI操作多めで記述していこうと思います。 バックエンドはPython+FastAPIでサクッと作って組み合わせていきます。 開発環境 以下の環境を準備してください。 インストール手順は説明しませんが、インストーラーのリンクは張っておきます。 Windows 10 Pro Docker Desktop for Windows を使うので、Pro環境を想定。 簡易的なことしかしないので、dockerが動作すればMac、Linuxでも良いです。 docker Docker Desktop for Windows で説明をします。 CUIに慣れていない人向けにGUIでの操作を記載しますが、詳しい人はCUIでの操作を推奨。 インストーラー Get Dokcerをクリックしてダウンロードし、インストーラーを実行する。 Visual Studio Code インストーラー Windowsをクリックしてダウンロードし、インストーラーを実行する。 Python,JavaScript,dockerfileの編集を行うので、以下の拡張機能を入れてください。 拡張機能 Visual Studioを起動して、左側の拡張機能のアイコンをクリックし、入力欄で以下を検索してインストールしてください。 名前 説明 Japanese Language Pack for Visual Studio Code 日本語環境 Python Python言語用 Docker Docker用 Remote - SSH リモート作業用 Remote - Containers リモート作業用 Remote - SSH: Explorer リモート作業用 Remote Development リモート作業用 docker環境 1.任意のフォルダを作成 エクスプローラーを右クリックして、[新規作成] - [フォルダー] をクリック。任意の名前を設定します。 例:sample 2.Visual Studio Codeで開く 1で作成したフォルダを開き、右クリックで、[Codeで開く] をクリックし、Visual Studio Codeで開きます。 3.dockerfileの作成 右クリックで[新しいファイル]をクリックします。 ファイル名にdockerfileを指定し、ファイルの内容は以下をコピペします。 FROM node:lts-alpine RUN apk update && apk add --virtual=module curl git python3 python3-dev py3-pip RUN npm install -g create-react-app RUN npm install axios RUN pip3 install uvicorn fastapi requests WORKDIR /usr/src/app EXPOSE 8000 3000 4.dockerfileをビルド dockerfileを右クリックして、[Build Image...]をクリックします。 イメージの名前を入力してEnterキー。(デフォルトのままでOK) 例:sample:latest ダウンロードに少し時間がかかります。 5.dockerのコンテナの作成 左のバーの"くじら"のアイコン(赤枠)をクリックします。 作成した名前のイメージがツリーで表示される(緑枠)ので右クリックして[Run Interactive]をクリックします。 コンテナが作成されるとツリーに表示されます。(青枠) 6.コンテナへの接続(ターミナル) コンテナを右クリックして[Attach Shell]をクリック。 黄枠の部分にターミナルが表示されます。 7.コンテナへの接続(Visual Studio Code) コンテナを右クリックして[Attach Visual Studio Code]をクリック。 別ウィンドウで、コンテナ内のフォルダでVisual Studio Codeが起動します。 [フォルダーを開く]ボタンをクリック。 開くパスを入力する欄が表示されるので、/usr/src/app を入力して[OK]ボタンをクリックする。 画面左に表示されるフォルダツリーでファイル操作ができます。 エクスプローラーからファイルをドロップしたり、右クリックで[ダウンロード]を実行することでコンテナ内のファイルをホストのPCに保存することができます。 フロントエンド(React) 6でコンテナに接続したターミナルで、以下を実行してReactのプロジェクトを作成します。 create-react-app my-app ダウンロードに時間がかかります。 作成されたmy-appフォルダに移動して、起動します。 cd my-app yarn start Chromeなどのブラウザを起動して、http://localhost:3000/ を表示するとデフォルトのページが表示されます。 バックエンド(Python+FastAPI) 7で表示したウィンドウを使いPython+FastAPIでバックエンドのREST APIを作成します。 React側から呼べるように、CORSを考慮して実装しておきます。 /usr/src/app の下にbg-appフォルダを作成し、その下にmain.pyを作成します。 main.py from fastapi import FastAPI from pydantic import BaseModel from starlette.middleware.cors import CORSMiddleware # uvicorn main:app --reload --host 0.0.0.0 app = FastAPI() app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"] ) class TestParam(BaseModel): param1 : str param2 : str # curl http://localhost:8000/ @app.get("/") def get_root(): return {"message": "fastapi sample"} # curl -X POST -H "Content-Type: application/json" -d '{"param1":"test1", "param2":"text2"}' http://localhost:8000/ @app.post("/") def post_root(testParam : TestParam): print(testParam) return testParam bg-appを右クリックして、[統合ターミナルで開く]をクリック。 表示されたターミナルで、以下を実行して起動する。 uvicorn main:app --reload --host 0.0.0.0 ブラウザを起動して、http://localhost:8000/ を表示するとjsonの応答が確認できます。 ソースのコメントに記載したcurlコマンドでも動作確認できます。 curl http://localhost:8000/ curl -X POST -H "Content-Type: application/json" -d '{"param1":"test1", "param2":"text2"}' http://localhost:8000/ React + FastAPI Reactのjsで、FastAPIに接続するコードを用意します。 my-app/srcフォルダ内にsample.jsを用意します。 sample.js import React from "react"; import axios from "axios"; class Sample extends React.Component { constructor(props) { super(props); this.state = { message1 : '', message2 : '' }; } handleClick = () => { axios .post("http://localhost:8000/" , { "param1": "hoge", "param2": "fuga"}) .then(res => { this.setState({ message1 : res.data.param1 , message2 : res.data.param2 }); }) .catch(err =>{ console.log(err); } ); }; render() { return ( <dev> <button onClick={this.handleClick}>POST</button> <p>メッセージ1={this.state.message1}</p> <p>メッセージ2={this.state.message2}</p> </dev> ); } } export default Sample; ボタンをクリックすると http://localhost:8000/ にPOSTでパラメータを渡して応答を画面に表示するSampleというコンポーネントを実装します。 my-app/src/App.jsにSampleコンポーネントを表示する処理を追加します。 App.js import logo from './logo.svg'; import './App.css'; import Sample from "./sample"; // 追加することで<Sample />が利用できる function App() { return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <p> Edit <code>src/App.js</code> and save to reload. </p> <a className="App-link" href="https://reactjs.org" target="_blank" rel="noopener noreferrer" > Learn React </a> <Sample /> </header> </div> ); } export default App; ブラウザを起動して、http://localhost:3000/ を表示するとPOSTボタンが追加されていることが確認できます。 POSTボタンをクリックするとFastAPIにPOSTリクエストを送り、応答を画面に表示します。 おわりに dockerの操作はターミナルでのCUI操作が多めになって、初心者向けじゃないと思っていたので、Visual Stusio Codeの拡張機能を利用したGUI操作で説明を記載してみました。 本来はターミナルでdockerコマンドを利用するべきですので、慣れてきたらdockerコマンドを覚えてください。 Reactは、サンプル実行したくらいなのであまり理解が深まっていません。 次回は、こちらで解説したマインスイーパを作ることで理解を深める記事の予定です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

React+FastAPI+dockerでWeb開発のお勉強

はじめに 仕事の進みが悪すぎて現実逃避したくなったので、気になっていたReactをさわってみることにしました。 4月ということで、新入社員や、学生の方でも作業しやすいようにGUI操作多めで記述していこうと思います。 バックエンドはPython+FastAPIでサクッと作って組み合わせていきます。 開発環境 以下の環境を準備してください。 インストール手順は説明しませんが、インストーラーのリンクは張っておきます。 Windows 10 Pro Docker Desktop for Windows を使うので、Pro環境を想定。 簡易的なことしかしないので、dockerが動作すればMac、Linuxでも良いです。 docker Docker Desktop for Windows で説明をします。 CUIに慣れていない人向けにGUIでの操作を記載しますが、詳しい人はCUIでの操作を推奨。 インストーラー Get Dokcerをクリックしてダウンロードし、インストーラーを実行する。 Visual Studio Code インストーラー Windowsをクリックしてダウンロードし、インストーラーを実行する。 Python,JavaScript,dockerfileの編集を行うので、以下の拡張機能を入れてください。 拡張機能 Visual Studioを起動して、左側の拡張機能のアイコンをクリックし、入力欄で以下を検索してインストールしてください。 名前 説明 Japanese Language Pack for Visual Studio Code 日本語環境 Python Python言語用 Docker Docker用 Remote - SSH リモート作業用 Remote - Containers リモート作業用 Remote - SSH: Explorer リモート作業用 Remote Development リモート作業用 docker環境 1.任意のフォルダを作成 エクスプローラーを右クリックして、[新規作成] - [フォルダー] をクリック。任意の名前を設定します。 例:sample 2.Visual Studio Codeで開く 1で作成したフォルダを開き、右クリックで、[Codeで開く] をクリックし、Visual Studio Codeで開きます。 3.dockerfileの作成 右クリックで[新しいファイル]をクリックします。 ファイル名にdockerfileを指定し、ファイルの内容は以下をコピペします。 FROM node:lts-alpine RUN apk update && apk add --virtual=module curl git python3 python3-dev py3-pip RUN npm install -g create-react-app RUN npm install axios RUN pip3 install uvicorn fastapi requests WORKDIR /usr/src/app EXPOSE 8000 3000 4.dockerfileをビルド dockerfileを右クリックして、[Build Image...]をクリックします。 イメージの名前を入力してEnterキー。(デフォルトのままでOK) 例:sample:latest ダウンロードに少し時間がかかります。 5.dockerのコンテナの作成 左のバーの"くじら"のアイコン(赤枠)をクリックします。 作成した名前のイメージがツリーで表示される(緑枠)ので右クリックして[Run Interactive]をクリックします。 コンテナが作成されるとツリーに表示されます。(青枠) 6.コンテナへの接続(ターミナル) コンテナを右クリックして[Attach Shell]をクリック。 黄枠の部分にターミナルが表示されます。 7.コンテナへの接続(Visual Studio Code) コンテナを右クリックして[Attach Visual Studio Code]をクリック。 別ウィンドウで、コンテナ内のフォルダでVisual Studio Codeが起動します。 [フォルダーを開く]ボタンをクリック。 開くパスを入力する欄が表示されるので、/usr/src/app を入力して[OK]ボタンをクリックする。 画面左に表示されるフォルダツリーでファイル操作ができます。 エクスプローラーからファイルをドロップしたり、右クリックで[ダウンロード]を実行することでコンテナ内のファイルをホストのPCに保存することができます。 フロントエンド(React) 6でコンテナに接続したターミナルで、以下を実行してReactのプロジェクトを作成します。 create-react-app my-app ダウンロードに時間がかかります。 作成されたmy-appフォルダに移動して、起動します。 cd my-app yarn start Chromeなどのブラウザを起動して、http://localhost:3000/ を表示するとデフォルトのページが表示されます。 バックエンド(Python+FastAPI) 7で表示したウィンドウを使いPython+FastAPIでバックエンドのREST APIを作成します。 React側から呼べるように、CORSを考慮して実装しておきます。 /usr/src/app の下にbg-appフォルダを作成し、その下にmain.pyを作成します。 main.py from fastapi import FastAPI from pydantic import BaseModel from starlette.middleware.cors import CORSMiddleware # uvicorn main:app --reload --host 0.0.0.0 app = FastAPI() app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"] ) class TestParam(BaseModel): param1 : str param2 : str # curl http://localhost:8000/ @app.get("/") def get_root(): return {"message": "fastapi sample"} # curl -X POST -H "Content-Type: application/json" -d '{"param1":"test1", "param2":"text2"}' http://localhost:8000/ @app.post("/") def post_root(testParam : TestParam): print(testParam) return testParam bg-appを右クリックして、[統合ターミナルで開く]をクリック。 表示されたターミナルで、以下を実行して起動する。 uvicorn main:app --reload --host 0.0.0.0 ブラウザを起動して、http://localhost:8000/ を表示するとjsonの応答が確認できます。 ソースのコメントに記載したcurlコマンドでも動作確認できます。 curl http://localhost:8000/ curl -X POST -H "Content-Type: application/json" -d '{"param1":"test1", "param2":"text2"}' http://localhost:8000/ React + FastAPI Reactのjsで、FastAPIに接続するコードを用意します。 my-app/srcフォルダ内にsample.jsを用意します。 sample.js import React from "react"; import axios from "axios"; class Sample extends React.Component { constructor(props) { super(props); this.state = { message1 : '', message2 : '' }; } handleClick = () => { axios .post("http://localhost:8000/" , { "param1": "hoge", "param2": "fuga"}) .then(res => { this.setState({ message1 : res.data.param1 , message2 : res.data.param2 }); }) .catch(err =>{ console.log(err); } ); }; render() { return ( <dev> <button onClick={this.handleClick}>POST</button> <p>メッセージ1={this.state.message1}</p> <p>メッセージ2={this.state.message2}</p> </dev> ); } } export default Sample; ボタンをクリックすると http://localhost:8000/ にPOSTでパラメータを渡して応答を画面に表示するSampleというコンポーネントを実装します。 my-app/src/App.jsにSampleコンポーネントを表示する処理を追加します。 App.js import logo from './logo.svg'; import './App.css'; import Sample from "./sample"; // 追加することで<Sample />が利用できる function App() { return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <p> Edit <code>src/App.js</code> and save to reload. </p> <a className="App-link" href="https://reactjs.org" target="_blank" rel="noopener noreferrer" > Learn React </a> <Sample /> </header> </div> ); } export default App; ブラウザを起動して、http://localhost:3000/ を表示するとPOSTボタンが追加されていることが確認できます。 POSTボタンをクリックするとFastAPIにPOSTリクエストを送り、応答を画面に表示します。 おわりに dockerの操作はターミナルでのCUI操作が多めになって、初心者向けじゃないと思っていたので、Visual Stusio Codeの拡張機能を利用したGUI操作で説明を記載してみました。 本来はターミナルでdockerコマンドを利用するべきですので、慣れてきたらdockerコマンドを覚えてください。 Reactは、サンプル実行したくらいなのであまり理解が深まっていません。 次回は、こちらで解説したマインスイーパを作ることで理解を深める記事の予定です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む