- 投稿日:2020-08-30T22:38:36+09:00
Material-uiでDate pickerを使うときの注意点
本記事の目的
ReactのCSSフレームワーク「Material-ui」で日時入力(Date/Time)をするためのフォームを実装する際に詰まったので、メモ。
Material-ui公式ドキュメント内の該当項目はこちら↓
https://material-ui.com/components/pickers/1. 必要なコンポーネント
公式ドキュメントの記載が不親切で、初心者には何が必要かいまいち分からなかった。
下記3つのコンポーネントの導入で動作しました。"date-fns": "^2.16.0", "@date-io/date-fns": "1.x" "@material-ui/pickers": "^3.2.10"※2020年8月時点のヴァージョン
注:ヴァージョン制限に注意、下記2.で解説date-fns以外にも、moment,luxion,dayjsがあるけど、
詳しくないのでMaterial-uiの公式ドキュメント内で採用されている、date-fnsを採用。
※比較記事見つけたら追記します。2. @date-ioのヴァージョン制限
これも公式ドキュメントをしっかり読めという話だけど、
https://material-ui-pickers.dev/
の中に、Important: For material-ui-pickers v3 use v1.x version of @date-io adapters.
※意訳:v3のmaterial-ui-pickersnにはv1.X台の@date-ioを使いなさい。とある。これを見逃してエラーにハマったので大事。
実装例
DatePickerコンポーネントの実装例を記載します。
useStateを上位から渡していますが、もっと良い方法があれば、ご指摘いただける嬉しいです。import React from 'react'; import { MuiPickersUtilsProvider, KeyboardDatePicker, } from '@material-ui/pickers'; import DateFnsUtils from '@date-io/date-fns'; const DatePicker = ({ selectedDate, setSelectedDate }) => { const handleDateChange = (date) => { setSelectedDate(date); }; return ( <MuiPickersUtilsProvider utils={DateFnsUtils}> <KeyboardDatePicker disableToolbar variant="inline" format="yyyy/MM/dd" value={selectedDate} onChange={handleDateChange} /> </MuiPickersUtilsProvider> ); }; export default DatePicker;
- 投稿日:2020-08-30T19:34:23+09:00
【React】なぜsuper(props)は必要なの?
元(?)記事
https://qiita.com/hand-dot/items/61a4b808f110b12e4281
とても参考になったのですが、もう少し噛み砕いてわかりやすく解説していきます?♂️
【疑問その1】なぜ、super()を呼び出すのか
結論から言うと
this.name
のようなthis
を伴う初期化を親クラスで行うため。下記はReact
ではないJSのクラスです。class Parent { constructor(name) { //ここで初期化している this.name = name; } } class Child extends Parent { constructor(name) { console.log(this.name); // エラーになる super(name); } } const test = new Child("佐藤");直感的に
this.name
が使えそうに感じるが、初期化(親クラスのconstructor
を実行)してないので、使えない。React
の場合も同様。// React.componentの内部 class Component { constructor(props) { this.props = props; // ... } } class Child extends React.component { constructor(props) { console.log(this.props); // エラーになる super(props); } }propsを渡す必要性
結論、親と自分のコンストラクターの実行が終わるまで、
this.props
は未定義だから。実は、React内部で
props
がインスタンスに割り当てられている。// React内部 const instance = new YourComponent(props); instance.props = props;しかし、これはコンストラクター実行後に行われる処理なので、コンストラクター内で
this.props
を使った処理を書けなくなってしまう。以上の理由から、super(props)を書きましょう。
何か間違っているところがありましたらご指摘よろしくお願いします?♂️
- 投稿日:2020-08-30T19:00:25+09:00
【React】stateについて学ぶ
stateとは
- コンポーネントが持つ状態のこと。
- クラスコンポーネントで使用される。(
hooks
は一旦置いておく。)- コンストラクタ内で初期値が決められる。
setState
で更新する。- 値が変更されると
render
される。import React from "react"; class Test extends React.Component { constructor(props) { super(props); this.state = { name: "佐藤", }; } render() { return ( <> <h1>{this.state.name}</h1> </> ); } } export default Test;次にstateの更新について。以下のように書かなくてはいけない。
this.state({ name = "山田" })以下のように書くのはNG。再レンダリングされないから。
jsx
this.state.name = "山田"
- 投稿日:2020-08-30T17:27:10+09:00
react で yarn startができなくなって困った
急にyarn startができなくて困ったので原因と経緯を書いておきます。
結果を先に言うとreact-scripts
を消してしまっていました…発生した事象
$ yarn start yarn run v1.22.5 $ react-scripts start /bin/sh: react-scripts: command not found error Command failed with exit code 127. info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.発生の経緯
久々に触ったアプリにて、
package installひとつづつやるのめんどくさいから、package.json一気に書き換えて…
よしyarn installして、とりあえずエラー出てないか起動してみよう....あれ?そもそも起動ができない…なぜだ…解決までの道筋
初めてみたエラーだ…なんだこれ…パニック…
とかなる前にまずはエラーメッセージを出してくれているのでちゃんと読む。/bin/sh: react-scripts: command not found
yarn曰く、原因はreact-scriptsがないですよ?と言っている。
あ…なるほど…これはどういうことか
$ yarn start
をした時に見ているのは
package.json(...省略) "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" }, (省略...)この部分。
ここでreact-scripts
呼んでいるのにそんなもの見つかりませんよ?正気ですか?と言われている。なるほど?では
react-scripts
はnode_modules/
にいるはず(と思っている)ので調べる。$ ls node_modules/ | grep react-scripts $あれ…ない?
$ ls -1 node_modules/ | grep react- babel-plugin-add-react-displayname babel-plugin-react-docgen babel-plugin-transform-react-remove-prop-types babel-preset-react-app connected-react-router create-react-context css-to-react-native enzyme-adapter-react-16 eslint-config-react-app eslint-plugin-react-hooks hoist-non-react-statics mini-create-react-context react-addons-create-fragment react-app-polyfill react-async-script react-circle react-clientside-effect react-color react-dev-utils react-div-100vh react-docgen react-dom react-draggable react-dropzone react-element-to-jsx-string react-error-overlay react-fast-compare react-focus-lock react-ga react-google-recaptcha react-gtm-module react-helmet react-helmet-async react-hot-loader react-hotkeys react-infinite-scroller react-input-autosize react-inspector react-is react-lifecycles-compat react-move react-native-get-random-values react-popper react-popper-tooltip react-pose react-redux react-router react-router-dom react-router-hash-link react-scroll react-select react-side-effect react-sizeme react-syntax-highlighter react-test-renderer react-textarea-autosize react-transition-group react-use storybook-react-routerやっぱりない…
package.jsonを見に行くと…
react-scripts
が消えている…解決
ということで
package.json
にreact-scripts
を追記して、yarn-install
して解決。まとめ
ちゃんとエラーメッセージで教えてくれているので、
初めてみるエラーだからってパニックになってはいけない。…あとエラーハンドリングする時は、
エラー対応した人がわかるようにエラーメッセンジャー作るの重要ですね。
気をつけます。
- 投稿日:2020-08-30T17:08:40+09:00
Firebase + redux-toolkit の学習備忘録
まず
本記事がqiita初投稿となります。
暖かい目でご覧いただければ幸いです。
※現在、追記&学習中ですここまでの経歴
- 自作でReactとReact Nativeでアプリケーションを作成しようと思った
- AWSのEC2でやってみよう
- なんか手作り感がすごい、、カッコよく手軽に作りたかった→そうだFirebaseを使おう!
- Redux嫌いだから、useContextで乗り切ろう
- useContextも意外と好きじゃないかも。。。
- redux-toolkitっていうのがあるらしい、試してみよう
- redux-toolkitマジで最強!! 使っていこう
- Firebase + redux-toolkit でどんなアプリもさくっと作れそうなテンプレ覚えてみよう ←今ここ
困ったこと
firebaseUIの機能だけ継承して独自UIにしたいのにできない。。。
できない。
独自UI使いたいならfirebaseUIは使わない or DOM非表示にしてクリックイベント発火させるしかない。。。
firebaseuiのuiConfig.callbacks.signInSuccessWithAuthResult内でdispatch実行してもstoreが更新されない。。。
react-redux-firebase を使ってなんとか解決
Firebase + redux-toolkitの日本語ドキュメントなさすぎ、公式もredux-toolkitに対応してなさすぎ問題
もしかしてと思って調べてみたら、そもそもFirebaseを使ってる日本のサービスがあんまり見つからなかった。
意外と流行っていないのかな個人開発ではとっかかりやすいから有名だけど、会社として開発するとなるとFirebaseは選択しないのかも。。。
redux-toolkitの非同期がなんかうまくできない
createAsyncThunkの返り値が action.payload に入るというルールを知らなかった
- 投稿日:2020-08-30T15:40:20+09:00
styled-componentsをTypescriptで使う
styled-components ✖️ Typescript
Typescriptでstyled-componentsを書く時に情報が少なかったので、いくつか
型定義
propsの型を定義するときは、次のようにジェネリクスで指定する
interface Props { color: string } const Sample = styled.div<Props>` color: ${(props) => { return props.color }} `例えば、buttonを属性ごとに色を変えたいときは
const Button = styled.button<{primary?: boolean}>` background: transparent; color: black; border: 2px solid black; width: 10em; ${props => props.primary && css` border: 2px solid skyblue; `} `; <Button>not primary</Button> <Button primary>primary</Button>条件分岐
また、if文を使ってスタイルを適用することも可能。
例えば、type
というpropsを適用して色を変化させるときは、こんな感じ。interface Props { type: 'SUCCESS' | 'FAIL'; } const Flash = styled.div<Props>` text-align: center; margin: 5em; color: black; width: 10em; opacity: 0.8; background-color: ${props => { switch (props.type) { case 'SUCCESS': return 'rgba(32, 153, 134, 0.9)'; case 'FAIL': return 'rgba(230, 65, 30, 1)'; default: return 'rgba(32, 153, 134, 0.9)'; } }}; `; const Wrapper = styled.div` display: flex; align-items: center; `; const Sample: FC = () => { return ( <Wrapper> <Flash type="SUCCESS">success</Flash> <Flash type="FAIL">fail</Flash> </Wrapper> ); };既存のcomponentを上書きしたいとき
typescriptとは関係ないですが、例えば基本の形はsemantic-uiなどのコンポーネントを使用したいが、色だけ変えたい時
import {Button} from 'semantic-ui-react'; const StyledButton = styled(Button)` margin: 20px !important; background: skyblue !important; `; <StyledButton>styled button</StyledButton>
- 投稿日:2020-08-30T12:54:24+09:00
「Vercel + freenom + Getform.io」構成で「爆速 + 管理費完全無料」のポートフォリオをGatsbyJSで作ったら幸福度が高まった話
こんにちは(๑╹ω╹๑ )
つい先月のエントリでGatsbyJSの魅力をお伝えしたばかりですが、
今日はそのGatsbyJSで開発したポートフォリオサイトの構成を紹介します?↓ 開発したポートフォリオサイトです
今回のエントリとは関係ないですが、
技術構成は下記のとおりです?
- React
- GatsbyJS
- Less
ポートフォリオサイトの構成について☺️
管理費完全無料は本当??
本当です??
- SPAサイトの静的ホスティング
- 独自ドメイン
- お問い合わせ管理
全ての管理費が無料です✨
※ 2020年8月30日現在
※ 詳細は以降に説明静的ホスティングサービスのVercelって何が無料??
- 満載のDevOps
- Git Integrationsで自動ビルド
- GitHub(プライベートリポジトリ可
- GitLab
- Bitbucket
- Integrations Marketplaceの利用も無料
- VercelイベントをSlackに通知する
- ビルド後にLightHouseで自動レポーティング
- Starterから簡単にプロジェクトを開始できる
- Gatsby.js
- Nuxt.js
- Angular
- Next.js
- Vue.js
- カスタムドメイン(50個まで
- 1ヶ月あたり100GBまでの転送量
- 自動でSSL化
- デプロイしたら自動でhttpsになっていた?
- Serverless FunctionsでAPIの実装
- 所謂FaaS
↑全てが無料です?
※ 個人利用プランの場合freenomで独自ドメインを無料で取得・更新する
ga
という独自ドメインを無料で取得できました?(個人開発ではいつも利用しています笑
正確には下記の制限があります?
.tk
、.ml
、.ga
、.cf
、.gq
ドメインが対象- 1〜12ヶ月の範囲でないと登録・更新できない(でも永久無料
- ネームサーバーの登録 or URL転送のみ
Getform.ioでお問い合わせの管理
お問い合わせフォームのエンドポイントになって、
それを管理できるサービスです?フォームを作成するたびにエンドポイントを発行してくれます!
個人利用の無料プランでは下記が無料です?
- 1フォーム
- 一ヶ月あたり100件のお問い合わせ
- 単一ファイルのアップロード
- 100MBのファイルストレージ
- デフォルトのThanksページ
- チームメンバーを1人招待する
- スパム保護
- Zapierとの統合
- Getform API
まとめ
個人のポートフォリオサイト規模の利用であれば、
不便なく、管理費も考えること無く利用できました?制作過程でGlitchという、静的ホスティングとペアプログラミングでコラボレーションが出来るサービスを見つけました!
- RAM:512MB
- ディレスク容量:200MB
の範囲であれば無料で利用できるみたいです?
近い内に少し触ってみようと思います?
- 投稿日:2020-08-30T11:58:41+09:00
【React】ミュータブルな操作とイミュータブルな操作
はじめに
業務で本格的にReactを触り始めて10ヶ月程経過しました。
実装を進める中でドキュメントを読んだり、ググったりする中で必ず目にするのが
- 「Reactはイミュータブルな操作を要請する」
- 「Reactでは破壊的な変更を伴う操作を行ってはいけない]
といった内容のものです。
なんとなくの理解で通り過ぎてしまっていたのですが、
そのせいでコンポーネントが期待どおり再レンダリングされず、画面が変化しないという現象に何度かぶち当たりました。
10ヶ月も基本的なことをスルーしていたので、調べて理解したことをまとめてみました。ミュータブル/イミュータブルとは
まずは言葉の意味から
- mutable (ミュータブル): 可変
- immutable (イミュータブル): 不変
ミュータブルな操作とは
元の状態の変更を伴う(可変)操作イミュータブルな操作とは
元の状態の変更を伴わない(不変)操作言葉だけだとつまりどう言うこと??となるので実際の配列操作をしてみます。
ミュータブルな操作/ミュータブルな操作
配列への要素の追加をしてみます。
const arr = ['1', '2', '3']; // ミュータブルな操作(イミュータブルではない操作) arr.push('4'); console.log(arr); // [ '1', '2', '3', '4' ]; // イミュータブルな操作(ミュータブルではない操作) const immutableArr = [...arr, '5']; console.log(immutableArr); // [ '1', '2', '3', '4', '5' ]実行結果だけを見てもパッと見違いがありません。
配列の操作で4と5という要素を加えた新しい配列が返ってきてるように見えます。ここで注目するのが元の配列と新しい配列のデータの参照先です。
arr.push('4');
とした時にはコピー元のconst arr = ['1', '2', '3'];
も
arr.push('4');
をした新しい配列も
arr = [ '1', '2', '3', '4' ];
という情報を参照します。
arr = ['1', '2', '3'];
`
の一つの情報(メモリ)に直接変更が加わり参照されるようになります。乱暴な言い方ですが、元の
arr = ['1', '2', '3'];
の情報はなくなります。
const immutableArr = [...arr, '5'];
とした場合には
コピー元の配列([ '1', '2', '3', '4' ])
と
新しい配列(immutableArr)
の参照先の情報をそれぞれ別々に持ちます。
arrは[ '1', '2', '3', '4' ]という情報を参照。
immutableArrは[ '1', '2', '3', '4', '5' ]という情報を参照。※言語は異なりますが、下記サイトの図解がわかりやすかったです。
https://kurochan-note.hatenablog.jp/entry/20110316/1300267023下記のようなオブジェクトの操作でも同様のことが行われます。
const obj = {name: 'a', type: 'old'}; // ミュータブルな操作(イミュータブルではない操作) obj.type = 'new'; console.log(obj); // { name: 'a', type: 'new' } // イミュータブルな操作(ミュータブルではない操作) const immutableObj = { ...obj, type: 'new' }; console.log(immutableObj); // { name: 'a', type: 'new' }なぜReactではイミュータブルな操作が必要なのか
上記を踏まえて、Reactでイミュータブルな操作が必要とされる理由は、
React がコンポーネントの変化をオブジェクトの 同一性(差分) チェックで検知しているためです。ミュータブルな操作をしてしまうとコピー元の情報も変更されてしまうため、
変更前と変更後の差分をReactが検知できなくなってしまいます。一方、イミュータブルな操作では変更前と変更後の情報をそれぞれ参照しているので、
Reactは差分を検知することができます。先ほどのオブジェクトの操作を例に取ると、
const obj = {name: 'a', type: 'old'}; // イミュータブルな操作(ミュータブルではない操作) const immutableObj = { ...obj, type: 'new' }; console.log(immutableObj); // { name: 'a', type: 'new' }
obj !== immutableObj
とした時にReactはコンポーネントに変化があったと検知することができます。しかしミュータブル(イミュータブルではない)な操作をした下記の場合、
const obj = {name: 'a', type: 'old'}; // ミュータブルな操作(イミュータブルではない操作) obj.type = 'new'; console.log(obj); // { name: 'a', type: 'new' }
obj.type = 'new';
とした後のobj
は初めとは異なったtypeの値を持ちますが、
obj !== obj
では変更を検知できないため、Reactは差分に気付けないのです。この変更の検知の仕組みを持つため、Reactではイミュータブルな操作が必要とされるのです。
なのでReactで配列操作やオブジェクト操作をする際には,
concat()
、Object.assign()
やスプレッド演算子
を用いたイミュータブルな操作をする必要があります。たどたどしい説明になってしましましたが、最後まで読んで頂きありがとうございました。
- 投稿日:2020-08-30T08:59:35+09:00
【ReduxToolkit】React,TypeScript,ReduxToolkitで最新の開発環境を爆速で構築するお話【非同期通信】
はじめに
- この記事を読むと、React-TypeScript-ReduxToolkitのSliceの作成から非同期通信まで理解することができます。
- 説明は最小限にとどめ、コードベースで進めていきます。
いざ、React-TypeScript-ReduxToolkitの環境構築
まずは何がともあれコマンドでReact-TypeScript-ReduxToolkitの環境を構築する。
create-react-app my-app --template redux-typescriptそして、以下コマンドで実行
npm run start もしくは yarn startこんな画面がでれば、開発環境構築完了です。
かわいいですよね。Reduxのロゴ。
筆者もこんなん考えれる人になりたいとです…。Redux-TypeScriptのtemplateの中身を見てみよう
そして、src/feauturesディレクトリを見てみましょう。
Counterディレクトリが入っているはずです。ReduxToolkitの特徴は
機能ごとにSliceという塊を作って整理していくことです。
なので、新たに機能を追加したい場合はこのtemplateと同じようにfeaturesの中にCounterのようなSliceを作ればOK。
では、非同期通信のSliceを作っていきましょう。
非同期通信のSliceを作成しよう!
お待ちかね、非同期通信のSliceを作っていきましょう。
では、名前をfetchとし、featuresディレクトリの内部に作成してください。
その中に2つTypeScriptのファイルを作成しましょう。
- Fetch.tsx
- fetchSlice.ts
こんな感じになりましたか?
DOMをreturnするファイルは拡張子を.tsxとし、関数などしか定義しないファイルは.tsとすればいい感じになりますね。
では、fetchSlice.tsから書いていきましょう!
今回、非同期通信のAPIはJSONPlaceholderのものを使用させていただきました。・ JSONPlaceholder
https://jsonplaceholder.typicode.com/usersそして、非同期通信なので、この子も忘れずにインストール
npm install axios もしくは yarn add axiosfetchSlice.ts
import {createSlice, createAsyncThunk } from '@reduxjs/toolkit' import axios from 'axios' import userData from './userData.json' import {RootState} from '../../app/store' type UserDataType = typeof userData type FetchType = { data: UserDataType } export const fetchGetData = createAsyncThunk('fetch/get', async () => { const res = axios.get<UserDataType>('https://jsonplaceholder.typicode.com/users') return res }) const initialState: FetchType = { data: userData } export const fetchSlice = createSlice({ name: 'fetch', initialState: initialState, reducers: {}, extraReducers: (builder) => { builder.addCase(fetchGetData.fulfilled, (state, action) => { return { ...state, data: action.payload.data } }) } }) export const selectData = (state: RootState) => state.fetch.data export default fetchSlice.reducerこれで完成です!
そして、app/store.tsをちょっとだけいじりましょう。
import { configureStore, ThunkAction, Action } from '@reduxjs/toolkit'; import counterReducer from '../features/counter/counterSlice'; import fetchReducer from '../features/fetch/fetchSlice' export const store = configureStore({ reducer: { counter: counterReducer, fetch: fetchReducer }, }); export type RootState = ReturnType<typeof store.getState>; export type AppThunk<ReturnType = void> = ThunkAction< ReturnType, RootState, unknown, Action<string> >;fetchReducerの部分を追加するだけですね!
これにて、Sliceの作成、およびStoreへの格納が完了です。
おつかれさまでした!
- 投稿日:2020-08-30T05:31:48+09:00
ReactとChart.jsでグラフを描画する
目的
グラフ描画に定評?がある「Chart.js」。
「react-chartjs-2」を使いReactアプリケーションでの実装方法の手順を理解していきます。
【公式サイト】
Chart.js:https://www.chartjs.org/
react-chartjs-2:https://github.com/jerairrest/react-chartjs-2完成イメージ
実装準備
実装に必要なモジュールをインストールしていきます。
Reactアプリケーションを作成
npx create-react-app chart-jsreact-chartjs-2をインストール
Chart.js2をReactにラッパーされたものを今回は使っています。
公式サイト:https://github.com/jerairrest/react-chartjs-2npm install --save react-chartjs-2 chart.jsChart.jsのコンポーネントを確認
用意されているChart.jsで使用できるグラフのコンポーネントはこちら。
それぞれがどんなグラフかは公式サイトを参照してください。export class Doughnut extends ChartComponent<ChartComponentProps> {} export class Pie extends ChartComponent<ChartComponentProps> {} export class Line extends ChartComponent<LinearComponentProps> {} export class Scatter extends ChartComponent<ChartComponentProps> {} export class Bar extends ChartComponent<LinearComponentProps> {} export class HorizontalBar extends ChartComponent<ChartComponentProps> {} export class Radar extends ChartComponent<ChartComponentProps> {} export class Polar extends ChartComponent<ChartComponentProps> {} export class Bubble extends ChartComponent<ChartComponentProps> {}実装
今回表示するデータは東京の年間の「降水量の月合計」を表示するグラフを作っていきます。
ちなみにデータは気象庁のページから取得できます。(https://www.data.jma.go.jp/gmd/risk/obsdl/index.php)では、以下から実装していくっ。
グラフを描画する。
早速実装コードとその画面はこんな感じです。
App.jsimport React from 'react'; import { Bar } from 'react-chartjs-2'; import './App.css'; function App() { const graphData= { labels: [ // 各ラベルを配列にすることで軸ラベルが改行されて表示される ['2019年', '1月'], ['2019年', '2月'], ['2019年', '3月'], ['2019年', '4月'], ['2019年', '5月'], ['2019年', '6月'], ['2019年', '7月'], ['2019年', '8月'], ['2019年', '9月'], ['2019年', '10月'], ['2019年', '11月'], ['2019年', '12月'], ], datasets: [ { data: [5.6, 7.2, 10.6, 13.6, 20, 21.8, 24.1, 28.4, 25.1, 19.4, 13.1, 8.5], label: '月別合計降水量(mm)', }, ], }; return ( <div className="App"> {/* グラフコンポーネントの呼び出し */} <Bar data={graphData} /> </div> ); } export default App;このようにコンポーネントに
data
プロパティを付けることでグラフを表示することが出来ます。
これだけではグラフとしてそっけないので、オプションを追加していきます。App.js//(省略) function App() { const graphData = { labels: [ // (省略) ], datasets: [ { data: [5.6, 7.2, 10.6, 13.6, 20, 21.8, 24.1, 28.4, 25.1, 19.4, 13.1, 8.5], backgroundColor: 'rgba(30, 144, 255, 1)', // <--追加 label: '月別合計降水量(mm)', }, ], }; const graphOption = { scales: { xAxes: [ // x軸設定 { scaleLabel: { // 軸ラベル設定 display: true, labelString: '2019年', }, }, ], yAxes: [ // y軸設定 { scaleLabel: { display: true, labelString: '合計降水量(mm)', }, ticks: { // 軸目盛設定 beginAtZero: true, callback: function (value, index, values) { return `${value}(mm)`; }, }, }, ], }, }; return ( <div className="App"> {/* グラフコンポーネントの呼び出し */} <Bar data={graphData} options={graphOption} /> </div> ); } export default App;画面はこんな感じ。
グラフの
datasets
に色を付け、グラフコンポーネントにoptions
を追加しました。。
これだけでも意外とそれっぽくなりますね。
オプションの各項目の詳細は公式サイトを参考にしてください。まとめ
グラフ描画のライブラリにはD3.jsが人気という話もあるが、簡単なグラフを表示するだけならChart.jsのほうがサクッとでき印象です。
次は複数のグラフを同時に表示する複合グラフを作っていこうと思います。
- 投稿日:2020-08-30T00:48:02+09:00
ReduxとFluxはどう違うのか
Reduxはわかった。Fluxとはなんなのだ?
React/Reduxは昨今のWebフロントではよく見る構成なので、学んでいる方は多いと思う。
Reduxの関連文献を読むと度々Fluxという言葉が出てくるがあれは一体なんなのか。この記事では、Reduxとの違いを意識しながらFluxを紐解いていく。
Fluxとはアーキテクチャである
Facebookが生み出したクライアントサイドウェブアプリ用のアーキテクチャである。
Reduxはライブラリの名前であるが、Fluxはアーキテクチャの名前である。つまり特定のライブラリを指す言葉ではない。
(とはいえfacebook/fluxがutilを提供しており、これが使われることが多い)このアーキテクチャの実装を助けるライブラリが多数生まれたが、その中で一際人気を誇ったのがRedux。
ReduxはFluxのような単一方向のデータパスに基づく設計思想になっているが構成要素に違いがある。なぜFluxなのか MVCでは難しい実装ケース
ReduxとFluxの話に入る前に、もう一つ有名なアーキテクチャのMVCの話を最初にする。
MVCモデルではどんな時に不都合なのだろうか。端的に書くとMVCでは1つのデータソースを複数箇所のUIから操作されるようなケースでコードが複雑になる。
公式の例ではチャットの未読数のカウント表示が挙げられている。
- チャットは不特定多数の人から送られ、その内どれかが既読になればカウントを-1する
- 2カ所からチャット開けるならそれぞれの箇所で既読時にカウントを-1するロジックをいれる
- 2カ所に存在するカウント表示にデータの変更を反映させる
このように、共通のデータを複数箇所から変更 & 参照する場合、Viewのデータソースとなる値をどこでどう管理するのかが難しくなる。
MVCでは複数箇所から更新され、複数箇所に対して更新を反映する複雑なデータフローになるところを、Fluxであれば単一で1方向のデータフローで表現することができる。Fluxの主要素
下記の要素がFluxの主要素と言われている。
- dispatcher
- store
- view
- action
いずれもReduxの経験者であればなんとなく耳にしたことがあるような単語ではあるが、それぞれ少しずつ意味合いが異なる。
dispatcher
storeに対してcallbackを登録し、呼び出しに応じてそれを起動する存在。
Action Creatorメソッドから呼び出され、新しいデータを持ったActionオブジェクトをStoreに伝える役割を持つ。
1つのdispatcherが複数のcallbackを登録することができ、データをブロードキャストすることができる。store
データを管理するオブジェクト。
getterを持つがsetterは持たず、dispatcherによって登録されたcallbackからのみ更新される。
Reduxとは異なり、storeは複数存在することができる。それぞれのstoreに対してdispatcherはcallbackを登録する。view
storeのデータを参照して作成されるアプリケーションの見た目の部分。
storeからデータを受け取るviewのことを Controller view と呼び、子孫コンポーネントに対してPropsを渡していく役割を持っている。
viewとController viewに分けることで、viewの責務をシンプルに保つことができる。Action
Actionはストアを更新する際の新しいデータを含んだオブジェクト。
dispatcherに対してActionを渡す関数をAction Creatorと呼ぶのはReduxと同じだが、FluxではActionsというオブジェクトのメソッドとしてAction Creatorが実装されることが多いらしい。(Flux公式でもAction Creatorはmethodであると書かれている)Fluxコードを体験してみたいなら
facebookがチュートリアル付きのexampleを提供しているので、Readme.mdに従ってコーディングをしてみるとFluxの書き味が体験できる。
flux-todomvcTodoMVCをFluxで作っていくチュートリアルで序盤は写経できるサンプルと解説、最後には解答無しの練習課題がついているので良い練習になる。
flux/utilを使用するので書き方はReduxに近いものがあり、Reduxでのアプリ制作経験があるの人ならそれほど時間をかけずに終えられると思う。
(筆者はこの記事を書くにあたってトライした)Reduxとの違い
上記のFluxの特徴と重複する部分はあるが、Reduxの違いにフォーカスしてまとめる。
dispatcherの存在
ReduxにDispatcherは無い。Store.dispatch()というメソッドはあるが別物。
上記の通り、dispatcherはstoreに対してcallbackを登録する役割を持つ。action creatorからDispatcher.dispatch()がcallされることからfluxの中心的な位置にいると言っていい。Reduxでは、dispatcherが登録するcallbackの役割をreducerが担っている。
action creatorの役割
dispatcherに関連してaction creatorの動きも少しだけ違う。
fluxのaction creatorはactionを引数にしてdispatcher.dispatchをcallする役割がある。Reduxにおけるaction creatorは呼ばれた時にactionを返却する。
creatorという名前のイメージにはこちらの方が近い。dispatcherとの結合がなくシンプル。middlewareが存在しない
Fluxはmiddlewareという仕組みを持たない。Dispatcher.dispatch()はあらかじめ登録したCallbackを呼ぶための処理であり、間に他の処理を挟むことはできない。
ReduxはmiddlewareによってdispatchされたActionをロギングしたり、エラーActionのハンドリングを行うなどReduxの処理フロー全体に影響を与えるような処理を含むことができる。
redux-thunk, redux-observableなどの非同期処理用のmiddlewareを活用することで、非同期処理の責務をらAction Creatorに持たせることができるようになるためComponentをシンプルに作りやすい。Fluxのstateは複数のstoreによって表現される
Fluxは複数のstoreを持つ。例えばTwitterのようなシステムであればUserInfoStoreとTweetListStoreのようなstoreを持つことになる。
これに対してReduxは1つのplain old Javascript object (POJO)でstateを表現する。アプリケーション全体の状態を扱いたいケースにおいては1つのオブジェクトである方が遥かに扱いやすい。
例えばSSRは、サーバーでstateを構築してクライアントに送信する必要があり単一のオブジェクトである恩恵を受けている。stateを追加する際にはFluxは新たなstoreを作成し、dispatcherから新たなcallbackを登録する。
Reduxは純粋な関数であるReducerを追加するのみであり、拡張がシンプル。終わりに
ReduxはFluxを基にして生まれたライブラリというだけあって使い勝手が良い面が多い。
Fluxを用いて新規にアプリケーションを作成する機会は少ないと思うが、アーキテクチャの話題では頻出単語なので正しく理解しておくと役立つと思う。