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

Reactで自動整形しようと思った時にハマったこと【VSCode】

はじめに

最近投稿を始めたTutuです。
VSCodeEsLintPrettierを使用して自動整形しようと思ったのですが、チュートリアルを読んでもなかなか適用されませんでした。
その時の自分の解決策を備忘録として残しておきます。

原因

以下の画像の「JavaScript React」という部分が「JavaScript」になっていたためReactの書き方である、jsx,tsx内で適用されなかっただけだった。
スクリーンショット 2020-10-11 23.17.18.png

解決策

該当部分をクリックして出てくる部分で下記画像の「Auto Detect」を選択し、「JavaScript React」と入力するだけ

※このままだと選択時のファイルにしか適用されないので、「.js」拡張子全体に適用したい場合は「Configure File Association for '.js'...」を選択後、同様の操作を行う

image.png

最後に

同じような現象でハマってしまっている方のために一応今回このような記事を投稿しましたが、初歩的すぎてあまり役に立たないような気がします....w

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Reactで作ったポートフォリオを個人的に振り返る(その1. npmモジュール)(のまた2)

前書き

業務でReactを触る機会が出てきそうなので、復習のため、以前作ったポートフォリオを個人的に振り返ります。

ソースコード
https://github.com/momonoki1990/house_work_memo_front
サービス
https://house-work-memo-front.herokuapp.com/home
(Herokuのフリープランで定期モニタリングも解除したので、めちゃ遅いはずです、すみません)

前回
Reactで作ったポートフォリオを個人的に振り返る(その1. npmモジュール)(のまた1)
https://qiita.com/momonoki1990/items/a1edd4fa922cd3ed3b14

使用したモジュール

package.json
"dependencies": {
    "@material-ui/core": "^4.11.0",
    "@material-ui/icons": "^4.9.1",
    "@testing-library/jest-dom": "^4.2.4",
    "@testing-library/react": "^9.5.0",
    "@testing-library/user-event": "^7.2.1",
    "@types/chart.js": "^2.9.23",
    "@types/jest": "^24.9.1",
    "@types/node": "^12.12.50",
    "@types/react": "^16.9.43",
    "@types/react-dom": "^16.9.8",
    "@types/react-redux": "^7.1.9",
    "@types/react-router-dom": "^5.1.5",
    "@types/redux-logger": "^3.0.8",
    "@types/redux-thunk": "^2.1.0",
    "axios": "^0.19.2",
    "chart.js": "^2.9.3",
    "chartjs-plugin-colorschemes": "^0.4.0",
    "connected-react-router": "^6.8.0",
    "date-fns": "^2.15.0",
    "react": "^16.13.1",
    "react-chartjs-2": "^2.10.0",
    "react-dom": "^16.13.1",
    "react-hook-form": "^6.1.0",
    "react-redux": "^7.2.0",
    "react-router-dom": "^5.2.0",
    "react-scripts": "^3.4.3",
    "redux": "^4.0.5",
    "redux-devtools": "^3.5.0",
    "redux-logger": "^3.0.6",
    "redux-thunk": "^2.3.0",
    "typescript": "^3.7.5",
    "typescript-fsa": "^3.0.0",
    "typescript-fsa-reducers": "^1.2.2"
  },

Redux関連

redux react-redux redux-thunk typescript-fsa typescript-fsa-reducers
@types/react-redux @types/redux-thunk redux-devtools

Reduxは、ReactJSが扱うUIのstate(状態)を管理をするためのフレームワークです。Reactではstateの管理するデータフローにFluxを提案していますが、ReduxはFluxの概念を拡張してより扱いやすく設計されています。
Reduxはstateを管理するためのライブラリーなので、React以外にもAngularJSやjQueryなどと併せて使用することもできますが、Reactと使用するのが一番相性がいいです。
Redux入門【ダイジェスト版】10分で理解するReduxの基礎
https://qiita.com/kitagawamac/items/49a1f03445b19cf407b7

Reactでは、stateという「状態」、というか個別の値を、コンポーネントごとに設定することができます。
Reduxは、コンポーネントごとのstateとは別に、stateを一元的に保持・管理できる場所だと思っています。
(要は、通常のstateがコンポーネントごとにローカルにstateを設定・参照できるのに対し、Reduxは、stateをグローバルに設定・参照できる)

Action
アクション(何が起きたのか)とそれに付随する情報を持つオブジェクト。
ActionをStoreへdispatch(送信)すると、Storeのstateが変更される。stateの変更は必ずActionを経由して行う(理由は後述)。
Reducer
Storeから受け取ったActionとstateに応じて、変更されたstateを返す純粋関数(同じ引数を渡されたら必ず同じ結果を返す関数)。
Store
アプリケーションの全てのstateを保持するオブジェクト。
Redux 入門 〜Reduxの基礎を理解する〜
https://qiita.com/soarflat/items/bd319695d156654bbe86

Providerの目的は2つ
1. Reactコンポーネント内でreact-reduxのconnect()関数を使えるようにすること
2. ラップしたコンポーネントにstore情報を渡すこと
ReactとReduxを結ぶパッケージ「react-redux」についてconnectの実装パターンを試す
https://qiita.com/MegaBlackLabel/items/df868e734d199071b883

→ちなみに、私のポートフォリオでは、connect使っていません(どうしたんだっけ?)
とりあえず、Providerの役割として、「ラップしたコンポーネントにstore情報を渡す」(要は、Reduxで管理しているstateを使えるようにする)だけ覚えておきます。

上記、Redux関連の用語を並べてみましたが、

reduxとreact-redux

reduxとreact-reduxって、どう使い分けるんだっけ?

redux
Redux本体です。

react-redux

Reduxは、Reactの一部ではなく、独立したソフトウェアです。そこで、ReactとReduxをシームレスに融合して使うためのパッケージを追加しておきます。
React.js & Next.js超入門(p.192)
https://www.amazon.co.jp/dp/B07X7DHZ9F/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1

具体的には、
createStore, combineReducers, applyMiddlewareなど、Reduxのストアを作るための機能や、Dispatch, AnyActionなどの型情報はredux、

Provider, useSelector, useDispatchなどの、ReactにReduxのstateやdispatchを渡す機能はreact-redux

と、とりまざっくりと覚えておくことにします。

redux-thunk

なんだっけ、これ。。。
確か、非同期処理を含むアクションをdispatchするのに必要で、createStoreでReduxのストアを作成する際に、applyMiddlewareでミドルウェアとして登録しておく必要があるんじゃなかったっけ。。。

Reduxでは基本的に、Action Creatorによって生成されたActionをStoreにディスパッチすることで単純な同期更新を行っています。そこにRedux-Thunkのようなミドルウェアを導入することでStoreの機能を拡張し、非同期ロジックを記述できるようにできます。
通常Action CreatorはActionオブジェクトを返しますが、Redux-Thunkを使用すると「Thunk」という関数を返すことができるようになります。これによってActionのディスパッチを遅らせたり、特定の条件が満たされた場合のみディスパッチできるようになります。
Redux-Thunkで非同期処理ができる仕組みを理解しよう
https://qiita.com/jima-r20/items/7fee2f00dbd1f302e373

仕組みはわかってないけど、大体あってた。
今はそれで良しとする。

typescript-fsa, typescript-fsa-reducers

これはあれですよね。あれ。なんかreducerとか何かを書くのを、簡単にするんじゃなかったでしたっけ...?
→TypeScriptでアクションクリエーターとレデューサーが簡単に書けるようになるんでした。

参考
reduxをtypescriptで使うならこれを使うしかない。(typescript-fsaがすごい)
https://qiita.com/m0a/items/703d64c74e43cb392a64

redux-devtools

インストールしておきながら、まったく使っていませんでした。
今後使ってみたいです。

参考
Reduxのデバックに必須!Redux DevToolsの使い方
https://harkerhack.com/react-redux-devtools/

後書き

一旦ここまでにします。
書こうと思って調べるほど、自分がよくわかってないことがわかりますね。
そのためにも、ゴミ記事でいいと思ってるんですが、それくらいだったら、ブログかなんかでやった方がいいのかな。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Reactの関数コンポーネントでMapbox GL JSを表示するデモ

はじめに

Vueが好きです(告白)
でもReactの方が流行ってるらしいのでキャッチアップしておかなきゃならんという事でcreate-react-appしてみました
とりあえずMapbox GL JSを表示したかったのですが、関数コンポーネントでちゃんと動く例がネット探してもなかったので備忘録兼ねて記事化しておきます

関数コンポーネント?

今まで使ってこなかったのであんまりよくわかってないですがクラスより関数の方が良いらしいです(関数型がトレンドという事でしょう)
ネット上で見つかるReact+Mapbox GL JSの例はほとんどクラスコンポーネントだったので、じゃあよりよいという関数コンポーネントでやってみようとしましたが、hooksがどうとか謎用語連発でちょっと困りました

https://sparkgeo.com/blog/build-a-react-mapboxgl-component-with-hooks/
参考サイト(でもこれをコピペしても動きません)

コード

App.tsx
import React, { CSSProperties, useEffect, useRef, useState } from 'react';
import mapboxgl from 'mapbox-gl';
import 'mapbox-gl/dist/mapbox-gl.css';

const styles: CSSProperties = {
    width: '100vw',
    height: 'calc(100vh - 80px)',
    position: 'absolute',
};

const App = () => {
    const [map, setMap] = useState(null);
    const mapContainer = useRef(null);

    useEffect(() => {
        const initializeMap = ({
            setMap,
            mapContainer,
        }: {
            setMap: any;
            mapContainer: any;
        }) => {
            const map = new mapboxgl.Map({
                container: mapContainer.current,
                style: 'YOUR_MAPBOX_STYLE_URL',
                center: [140, 44.0],
                zoom: 5,
            });

            map.on('load', () => {
                setMap(map);
                map.resize();
            });
        };

        if (!map) initializeMap({ setMap, mapContainer });
    }, [map]);

    return <div ref={mapContainer} style={styles} />;
};

export default App;

メモ

リファレンス読んでないしほぼ語れる事がないのでほとんど推測

  • useState()によりコンポーネント内の変数を1箇所で管理する(っぽい、たぶんgetterとsetterを提供してる)
  • useRef()でクラス内のhtml的参照を変数で管理する(っぽい)
  • CSSProperties、オブジェクト的にCSS書けるの強そう
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Reactで作ったポートフォリオを個人的に振り返る(その1. npmモジュール)(のまた1)

前書き

業務でReactを触る機会が出てきそうなので、復習のため、以前作ったポートフォリオを個人的に振り返ります。

ソースコード
https://github.com/momonoki1990/house_work_memo_front
サービス
https://house-work-memo-front.herokuapp.com/home
(Herokuのフリープランで定期モニタリングも解除したので、めちゃ遅いはずです、すみません)

ちなみに、定期モニタリングの参考
Herokuの無料dynoをスリープさせないで24時間稼働させる4つの方法
https://casualdevelopers.com/tech-tips/how-to-prevent-idling-of-free-dyno-on-heroku/
→UptimeRobotを使ってました。

使用したモジュール

package.json
"dependencies": {
    "@material-ui/core": "^4.11.0",
    "@material-ui/icons": "^4.9.1",
    "@testing-library/jest-dom": "^4.2.4",
    "@testing-library/react": "^9.5.0",
    "@testing-library/user-event": "^7.2.1",
    "@types/chart.js": "^2.9.23",
    "@types/jest": "^24.9.1",
    "@types/node": "^12.12.50",
    "@types/react": "^16.9.43",
    "@types/react-dom": "^16.9.8",
    "@types/react-redux": "^7.1.9",
    "@types/react-router-dom": "^5.1.5",
    "@types/redux-logger": "^3.0.8",
    "@types/redux-thunk": "^2.1.0",
    "axios": "^0.19.2",
    "chart.js": "^2.9.3",
    "chartjs-plugin-colorschemes": "^0.4.0",
    "connected-react-router": "^6.8.0",
    "date-fns": "^2.15.0",
    "react": "^16.13.1",
    "react-chartjs-2": "^2.10.0",
    "react-dom": "^16.13.1",
    "react-hook-form": "^6.1.0",
    "react-redux": "^7.2.0",
    "react-router-dom": "^5.2.0",
    "react-scripts": "^3.4.3",
    "redux": "^4.0.5",
    "redux-devtools": "^3.5.0",
    "redux-logger": "^3.0.6",
    "redux-thunk": "^2.3.0",
    "typescript": "^3.7.5",
    "typescript-fsa": "^3.0.0",
    "typescript-fsa-reducers": "^1.2.2"
  },

順番に解説(というかほとんど忘れているので復習しつつ)

Material UI

Material UIとは?
公式:Material UI
GoogleのMaterialデザインをベースに開発された、UIコンポーネントライブラリです。
お手軽にMaterialデザインを取り入れられることに加えて、コンポーネントの種類が豊富に用意されているため、それらを組み合わせるだけでも見栄えの良いものを作ることができます。
一からコンポーネントを作るのはつらいとか、デザインを考えるのが難しいとか、それらに工数をあまりかけたくないなどの場合にもおすすめです。
React向けのUIコンポーネントライブラリはいろんなものがありますが、その中で人気の高いライブラリでもあります。
React入門 ~Material UI編~
https://qiita.com/h-yoshikawa/items/efa33101b0a02cba7759

@material-ui/core
Material UIの基本のモジュール。基本的なコンポーネントが格納されている。
Material UI
https://material-ui.com/

@material-ui/icons
SVGアイコンが格納されています。
Material Icons
https://material-ui.com/components/material-icons/

こんな感じで使います。

HomePage.tsx
import Button from '@material-ui/core/Button';
import DeleteIcon from '@material-ui/icons/Delete';

<Button variant="contained" color="secondary" data-key={work.id} onClick={handleDelete} startIcon={<DeleteIcon />}>削除</Button> :
<DeleteIcon color='secondary' />

スクリーンショット 2020-10-11 15.02.06.png

@types/nodeとCreate React AppとReact DOM

@types/node
node.jsの型ファイル。TypeScriptを使うのに必要。
というか、npx create-react-app sample_react_ts_app --typescriptでReactプロジェクトを作成した時点で、デフォルトで入っている。

ちなみに、create-react-appはnpmモジュールで、グローバルにインストールして使う。
Reactアプリケーションの雛形がコマンド一発で作れる。

参考
Create React Appで環境構築 – React入門
https://www.to-r.net/media/react-tutorial12/

npm install -g create-react-app
npx create-react-app sample_react_ts_app --typescript 

create-react-appを使用した場合にデフォルトでインストール済みのモジュール。

package.json
"dependencies": {
    "@testing-library/jest-dom": "^4.2.4",
    "@testing-library/react": "^9.3.2",
    "@testing-library/user-event": "^7.1.2",
    "@types/jest": "^24.0.0",
    "@types/node": "^12.0.0",
    "@types/react": "^16.9.0",
    "@types/react-dom": "^16.9.0",
    "react": "^16.13.1",
    "react-dom": "^16.13.1",
    "react-scripts": "3.4.3",
    "typescript": "~3.7.2"
  },

そういえば、react-domってなんだっけ?

react-dom パッケージには、DOM 固有のメソッドが用意されており、アプリケーションのトップレベルで使用したり、必要に応じて React モデルから外れるための避難ハッチとして使用できます。ほとんどのコンポーネントでは、このモジュールを使用する必要はないはずです。
render()
hydrate()
unmountComponentAtNode()
findDOMNode()
createPortal()
ReactDOM
https://ja.reactjs.org/docs/react-dom.html

create-react-appで作ったプロジェクトのsrc/index.tsxはこんな感じ。

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

→「renderぐらいでしか使わない」くらいの認識でいることにしよう。。。

ちなみに、reactはReact本体で、型定義に使ったり、Hookとかをimportして使う。

HomePage.tsx
import React, { useEffect, MouseEvent } from 'react';

// コンポーネント関数
const HomePage: React.FC = (props: any) => { return ()}

// useEffect Hook
useEffect(() => {
    dispatch(defaultHomeAction());
}, []);

// 削除ボタンの処理
const handleDelete = (event: MouseEvent<HTMLButtonElement>) => {
  dispatch(deleteWorkOfHome(event.currentTarget.getAttribute('data-key')));
}

後書き

長くなってしまったので、一旦ここで締めます。
そもそも、Reactの仕組み、仮想DOMとかってなんなんだっけ...?
調べてまとめたい。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

React学んでみた Hooks API createContext useContext

React

海外で多く扱われているのjsのFW/ライブラリは

React

一強です。

https://note.com/erukiti/n/na654ad7bd9bb

こちらの記事を見ていただけると納得いただけるのではないでしょうか?

自分の目的などと照らし合わせると確実にReactの学習は避けて通れないものになるので
これからキャッチアップを目指していきます。

もちろん現場で学ぶのが一番ではあるので
サクッとキャッチアップした後はアルバイトでも入ってみたい気持ちが強いです。

Reactの状態管理のベストプラクティス

こちらのサイトに掲載されています。
https://ics.media/entry/200409/

現状3つの手法があるようですね。

Hooks APIによる useContext createContext

これらを使うことで状態管理をより楽に実装していきます。
今回のサービスのディレクトリ構成になります。
全て使うわけではありません。

スクリーンショット 2020-10-11 13.29.07.png

rootコンポーネントに全体の状態管理のパラメータを渡します。

App.js
import React, {createContext, useState, useReducer} from 'react'
import ReactDom from 'react-dom'

import {BrowserRouter, Route, Switch} from "react-router-dom";

import GlobalNav from "./GlobalNav";
import Home from "./Home";
import Maxims from './maxim/Maxims'
import Post from "./Post";
import Edit from "./Edit";
import Setting from './Setting'

import SiteContext from "../contexts/SiteContext";
import reducer from '../reducers'

export const MaximContext = createContext()



const App = () => {
    const initialState = {
        maxims: [
            {
                id: 1,
                maxim: 'バレーは上を向くスポーツだ',
                who: '鵜飼コーチ',
                category: 'スポーツ',
                description: 'ハイキュー白鳥戦',
                oneWord: '武者震いしました',
            }
        ]
    }
    const [state, dispatch] = useReducer(reducer, initialState)


    return (
        <BrowserRouter>
            <GlobalNav/>
            <Switch>
                <SiteContext.Provider value={{state, dispatch}}>
                    <Route exact path="/" component={Home}/>
                    <Route exact path="/maxims" component={Maxims}/>
                    <Route exact path="/post" component={Post}/>
                    <Route exact path="/edit" component={Edit}/>
                    <Route exact path="/setting" component={Setting}/>
                </SiteContext.Provider>
            </Switch>
        </BrowserRouter>
    )
}

if (document.getElementById('app')) {
    ReactDom.render(<App/>, document.getElementById('app'))
}

以下で全体のstateを渡すためのcontextをimportしてきています。

App.js
import SiteContext from "../contexts/SiteContext";

以下で全体のstateを渡すためのcontextを作成しています。

SiteContext.js
import { createContext  } from 'react'

const SiteContext = createContext()

export default SiteContext

以下で子孫コンポーネントで利用できるように対応しています。

App.js
<SiteContext.Provider value={{state, dispatch}}>
App.js
    ...
    <BrowserRouter>
            <GlobalNav/>
            <Switch>
                <SiteContext.Provider value={{state, dispatch}}>
                    <Route exact path="/" component={Home}/>
                    <Route exact path="/maxims" component={Maxims}/>
                    <Route exact path="/post" component={Post}/>
                    <Route exact path="/edit" component={Edit}/>
                    <Route exact path="/setting" component={Setting}/>
                </SiteContext.Provider>
            </Switch>
        </BrowserRouter>
     ...

子コンポーネントで用いる

今回の構成はPOSTコンポーネントで投稿したものを
LIST画面で表示させていくというものになっています。

今回はPOST コンポーネントの箇所は省略させていただきます。

今後改めてまとめます。

※Maximというのは名言という意味で利用しています。

以下のMaximsファイルはmaximを複数持っておりそれらをcomponentに渡します。

Maxims.jsx
import React, { useContext } from 'react'

import SiteContext  from "../../contexts/SiteContext";
import Maxim from './maxim'

const Maxims = () => {
    const {state} = useContext(SiteContext);

    console.log(state.maxims);

    return (
        <div>
            <h1>List</h1>
            <div>
                <img src="" alt=""/>
                {state.maxims.map((maxim, index) => (<Maxim key={index} maxim={maxim}/>))
                    }
                )
                })}
                <div>


                </div>
            </div>
        </div>
    )
}

export default Maxims

以下で子コンポーネントに値を渡しています。

maxims.jsx
{state.maxims.map((maxim, index) => (<Maxim key={index} maxim={maxim}/>))

以下のmaxim.jsxファイルでは
親のmaximsから受け取ったmaximsをそれぞれ表示させています。

maxim.jsx
import React, {useState, useContext, useReducer} from 'react'

const Maxim = ({maxim}) => {

    return (
        <div>
            <div>
                <h3>ID</h3>
                {
                    maxim.id
                }
                <h3>名言</h3>
                {
                    maxim.maxim
                }
                <h3>誰が</h3>
                {
                    maxim.who
                }
                <h3>カテゴリ</h3>
                {
                    maxim.category
                }
                <h3>概要</h3>
                {
                    maxim.description
                }
                <h3>一言</h3>
                {
                    maxim.oneWord
                }
            </div>
        </div>
    )
}

export default Maxim

親のmaximsから受け取ったmaximを表示させます。

このような形で親に保存されている値をグローバルに値を用いることができます。

このhooksの状態管理でいいなと思ったのが
渡したい階層にだけ必要な値を渡せるというところですね。

順序としては

  • createContextで必要な値を格納
  • 親にProviderを設置
  • 子コンポーネントでuseContextの引数に作ったcontextを渡す。
  • 受け取った値を描画などで用いる。

の順になります。

自分でまとめてみるとかなり内容が整理されました。
やはり言語化作業は大事ですね。

値の変更(useReducer)に関しては改めて投稿できればと思っています。

これからも学んだことはしっかり言葉にして誰かに伝えられるように発信していきます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Firebaseを使ってみた 〜第三章 Firestoreからデータを取得する 〜

React Hooksを使いチャットボットアプリを作成しています。

この章ではFirestoreに保存した中から初期データを取得するまでを行います。

第一章 サービスをデプロイする
第二章 Firestoreにデータを保存する
第三章 Firestoreからデータを取得する

Firestoreを使う準備の流れ

1. config.jsファイルを作成する
2. エントリポイントを作成する
3. 初期データを取得する
4. まとめ

1. config.jsファイルを作成する

srcディレクトリ配下に「firebase」ディレクトリを作成し、その中に「config.js」ファイルを作成します。
Firebaseのページに移り、「プロジェクトを設定」画面へ遷移します。
スクリーンショット 2020-10-11 10.43.44.png

の下部にあるFirebase SDK snippetの構成にチェックを入れ、下に記載してあるコードをコピーしconfig.jsファイルに貼り付けます。
スクリーンショット 2020-10-11 10.44.22.png

貼り付けた内容を他の画面で使うので、exportしておきます。

firebase/config.js
const firebaseConfig = {
  apiKey: "******",
  authDomain: "******",
  databaseURL:"******",
  projectId: "******",
  storageBucket: "******",
  messagingSenderId: "******",
  appId: "******",
  measurementId: "******"
};

export default firebaseConfig

こちらの内容はGitHubなどに公開して問題ない内容のようですが、firestoreのセキュリティ設定をしておかないと簡単に書き込みをされてしまうので注意してください。(セキュリティ設定に関してはこちら

2. エントリポイントを作成する

firebaseディレクトリ配下に「index.js」ファイルを作成し以下記述をします。

firebase/index.js
import firebase from 'firebase/app'        //firebaseを読み込み
import 'firebase/firestore'                //firebaseの中のfirestoreを読み込み
import firestoreConfig from './congfig'    //先ほど作成したconfigファイルを読み込み

firebase.initializeApp(firesbaseConfig);   //firebaseを初期化
export const db = firebase.firestore();    //初期化したfirebaseのfirestoreを使う

3. Firestoreからデータを取得する

Firestoreからデータを取得していきます。まず、先ほど作成したdbをインポートします。

src/App.jsx
import { db } from './firebase/index'

useEffectを使い、ページ読み込み時に全データを取得するようにします。
async,await付きの即時関数で記述していきます。(即時関数について参考記事

src/App.jsx
import React, {useState, useEffect} from 'react'
import { db } from './firebase/index'

const App = () => {
 const [dataset, setDataset] = useState({});

  useEffect(() => {
    (async () => {
      const initDataset = {};
      await db.collection('[チャットボットのjsonファイルで設定したキー]').get().then(snapshots => {
        snapshots.forEach(doc => {
          const id = doc.id
          const data = doc.data()
          initDataset[id] = data
        })
        setDataset(initDataset)
      })
    })()
  },[])

ここで行っていることは以下です。

  • collectionにアクセスし、データ(doc)を取得(データはsnapshotsに全て格納される)
  • snapshotsの中身をforEachで回し、id,dataを取り出す
  • 取り出したidをキーにinitDatasetの中にデータを格納する

あとは任意の場所でinitDatasetからidをキーにデータを取り出して使います。

4. まとめ

この章ではエントリポイントを作成し、Firestoreに格納したデータを取得しました。

今回初めて使ったみたのですが、記述すべき内容が把握できればとても簡単にできることがわかりました。手軽にバックエンド環境を用意したい方にはお勧めです!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Firebaseを使ってみた 〜第二章 Firestoreにデータを保存する 〜

React Hooksを使いチャットボットアプリを作成しています。

この章ではAPIを使いFirestoreにチャットボットアプリで使うデータを保存していきます。

第一章 サービスをデプロイする
第二章 Firestoreにデータを保存する
第三章 Firestoreからデータを取得する 

Firestoreにデータを保存する までの流れ

1. データファイルを作成する
2. Cloud Functionsをインポートして初期化する
3. https関数を作成する
4. デプロイ する
5. APIを叩く
6. まとめ

1. データファイルを作成する

json型のデータファイルを生成します。
(jsonファイルの書き方が分からない・・・という場合はこちら参考にしてみてください)

私はチャットボットで使う応答内容やユーザーの選択肢などをjson型で作成しました。

2. Cloud Functionsをインポートして初期化する

Cloud Functionsをインポートし、Firebase Admin SDK を初期化します。
こちらを参考にしました。(jsの場合の書き方もありました)

functions/src/index.ts
import * as functions from 'firebase-functions'; 
import * as admin from "firebase-admin"; 
admin.initializeApp(); 
const db = admin.firestore();

3. https関数を作成する

APIからのレスポンスを返すための関数を作成します。
response、statusCode、bodyを受け取ります。

functions/src/index.ts
const sendResponse = (response: functions.Response, statusCode: number, body: any) => {
  response.send({
    statusCode,
    body: JSON.stringify(body)
  })
}

外部から関数を呼び出すため「export」をつけます。
今回はすべて「POST」を使うので、POST以外はエラーになるよう記述します。

functions/src/index.ts
export const addDataset = functions.https.onRequest(async(req: any, res:any) => {
  if(req.method !== 'POST') {
    sendResponse(res, 405, {error: 'Invalid Request'})
  } else {
    const dataset = req.body
    for(const key of Object.keys(dataset)) {
      const data = dataset[key]
      await db.collection('contents').doc(key).set(data)  
      //'contents'の部分は任意のcollection名でOKです
    }
    sendResponse(res, 200, {message: 'Successfully added dataset!'})
  }
})

参考:https://firebase.google.com/docs/functions/http-events?hl=ja

余談ですが、collection、document、dataについて曖昧な場合はこちらのページに図で解説があるので見てみてください。

4. デプロイ する

デプロイ コマンドを実行します。

$ firebase deploy

デプロイ 完了後、FirebaseのFunctionsに先ほど作成した関数名でデータが生成されます。

スクリーンショット 2020-10-06 19.40.20.png

「リクエスト」の下に記述されているURLをコピーしておきましょう。(次で使います)

5. APIを叩く

1.で作成したデータファイルがあるディレクトリまで移動します。
移動したら、以下のcurlコマンドでAPIを叩きます。

curl -X POST -H "Content-Type:application/json" -d @[作成したデータファイル名].json [先ほどコピーしたURL]

ステータスコード200が返ってくれば成功です。

Cloud Firestoreにデータが格納されていることを確認します。
スクリーンショット 2020-10-06 19.54.52.png

6. まとめ

この章ではFirebaseでプロジェクトを作成し、FirestoreにAPIを使ってデータを格納するところまで行いました。

続いてFirestoreに格納したデータを取得して使っていきます。(第三章へ・・・)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Firebaseを使ってみた 〜第一章 サービスをデプロイする 〜

React Hooksを使いチャットボットアプリを作成しています。(その辺の内容はいつかの記事で…)
バックエンド環境はFirebaseを使ってみました。設定内容やデプロイ までの過程を三章構成で記録しておきます。

第一章 サービスをデプロイする
第二章 Firestoreにデータを保存する
第三章 Firestoreからデータを取得する 

Firebaseとは

Googleが提供しているBaaS(※)
バックエンド側の開発工数を抑え、アプリ側の開発に注力できるのがメリットです。

※BaaS:backend as a serviceの略
    アプリ開発におけるバックエンド環境を提供してくれるサービス

デプロイ までの流れ

1. プロジェクトを作成する
2. 諸々設定をする
3. パッケージをインストールする
4. Firebaseにローカル環境を構築する
5. デプロイ する

1. プロジェクトを作成する

Firebaseにログインしてプロジェクトを作成します。
(Googleアカウントでログイン可能)
スクリーンショット 2020-10-03 12.58.49.png

プロジェクトに名前をつけます。
スクリーンショット 2020-10-03 13.02.53.png

ここのチェックはどちらでもOKだと思います。(私は一旦つけたままで・・)
スクリーンショット 2020-10-03 13.03.10.png

ご自身のアカウントを選択して、「プロジェクト作成」をクリック
スクリーンショット 2020-10-03 13.03.35.png

しばらくするとプロジェクトが生成されます。

2. 諸々設定をする

ここから諸々設定していきます。
まず、リソースロケーションの設定を行っていきます。

歯車マークから「プロジェクトを設定」を選択します。
スクリーンショット 2020-10-03 13.09.56.png

リソースロケーションを設定します。
スクリーンショット 2020-10-03 13.10.58.png

「asia-northeast1」を選択します。
※ここで選択を間違えると後から修正できず面倒なので注意します。
スクリーンショット 2020-10-03 13.12.55.png

そのまま同じ設定ページの下部にあるマイアプリを選択していきます。
今回はWebアプリを作成したいのでコードマークを選びました。
スクリーンショット 2020-10-03 13.17.00.png

アプリのニックネーム(プロジェクト名と同じでいいと思います)を入力し、
「このアプリ〜」にチェックを入れて、「アプリを登録」をクリックします。
スクリーンショット 2020-10-03 13.18.11.png

「Firebase SDKの追加」〜など全て「次へ」で遷移をし、最後に「コンソールに進む」を選択します。
スクリーンショット 2020-10-03 13.19.33.png

3. パッケージをインストールする

firebase-toolsをグローバルインストールします。(すでにインストール済みの場合は対応不要です。)

npm install -g firebase-tools

作業ディレクトリに移動し、以下のコマンドを実行します。

npm install --save firebase

完了後、package.jsonファイルに最新のfirebaseが追加されたことが確認します。

4. Firebaseにローカル環境を構築する

以下のコマンドを実行してFirebaseにログインします。

firebase login

以下の内容を聞かれるので、そのままEnterを押して許可します。
その後Firebaseのアクセス許可画面が出力されるので、同じく許可をします。成功画面を確認してターミナルに戻ります。

? Allow Firebase to collect anonymous CLI usage information? (Y/n)

次に以下のコマンドを実行し、先ほど作成したFirebaseの環境へローカルの内容を接続させます。

firebase init

「FIREBASE」の文字が出力されれば成功です。
続いて以下設定をしていきます。

まず1つ目、どのサービスを使うか選択します。
矢印キーで移動、spaceキーで選択、Enterキーで確定できます。
今回私は「Firestore」、「Functions」、「Hosting」の3つを使いました。

? Which Firebase CLI features do you want to set up for this folder? Press Space to select features, then Enter to confirm your choices. (Press 
<space> to select, <a> to toggle all, <i> to invert selection)
❯◯ Database: Deploy Firebase Realtime Database Rules
 ◯ Firestore: Deploy rules and create indexes for Firestore
 ◯ Functions: Configure and deploy Cloud Functions
 ◯ Hosting: Configure and deploy Firebase Hosting sites
 ◯ Storage: Deploy Cloud Storage security rules
 ◯ Emulators: Set up local emulators for Firebase features
 ◯ Remote Config: Get, deploy, and rollback configurations for Remote Config

先ほどFirebaseの中でプロジェクトを作成したので、「Use an existing project」を選択、作成したプロジェクト名を選びます。

? Please select an option: (Use arrow keys)
❯ Use an existing project 
  Create a new project 
  Add Firebase to an existing Google Cloud Platform project 
  Don't set up a default project 

以下質問が続きますが、特にデフォルトで問題ないのでそのままEnterで進みます。

? What file should be used for Firestore Rules? (firestore.rules)
? What file should be used for Firestore indexes? (firestore.indexes.json) 

Cloud Functionsをどの言語で作るか聞かれます。使いたい方を選択します。
その後選択した言語により諸々聞かれますがそのままYES(Enter)で進みます。

? What language would you like to use to write Cloud Functions? (Use arrow keys)
❯ JavaScript 
  TypeScript 

本番用のフォルダを聞かれます。デフォルトは「public」ですが、
今回create-react-appで作ったReactのサービスをデプロイ したいので、ここは「build」を入力します。

? What do you want to use as your public directory? (public) 

デフォルトはNOですが、今回シングルページ で作成したいのでYESで進みます。

? Configure as a single-page app (rewrite all urls to /index.html)? (y/N)

エディタを見てもらうと以下のファイルが生成されていることを確認できます。

スクリーンショット 2020-10-11 9.37.58.png

以上で構築終了です!

5. デプロイ する

ターミナルで以下コマンドを実行します。
まだビルドしていない場合は先に「$ npm run build」を行い、下記コマンドを実行します。

firebase deploy

完了後、Hosting URLが生成されるのでそちらをブラウザで確認します。

6. まとめ

以上でFirebaseへのサービスデプロイ が完了しました。
いくつかの設定を行うだけで簡単にデプロイ ができました。続いてFirestore(データベース)に使用するデータを保存していきます。(第二章へ・・・)

7. APPENDIX

  • firestoreのセキュリティを見直す
    自由に書き込みができないように設定します。詳しいセキュリティ内容は こちらから確認できます。
firestore.rules
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, 
      allow write: if request.auth.uid != null;
    }
  }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LaravelでReactを使う私的まとめ

Laravel Mix

  • フロントエンドのアセットをコンパイル、バンドルしてくれる
  • 中身はwebpackでwebpackの設定をわかりやすく掛けるようにラッピングしてある
  • sass,babelなどは最初から用意されている

バンドル

バンドルとは、束(ねる)、塊などの意味を持つ英単語で、単体でも提供可能な製品やサービスを、複数組み合わせてセットで販売したり、別の製品やサービスに付属して販売、提供することをこのように呼ぶ。
引用:バンドル 【 bundle 】

つまり違うものを組み合わせてくれるってことかな

Laravel Mixの実行

npm run dex

npm run dev を実行すると、
package.jsonに書いてあるスクリプトが実行され、
設定ファイルに記述したコンパイルやバンドルが実行される。

npm run production の場合は圧縮されたファイルが出力される。
引用:Laravel Mixとは?webpackをより便利に、簡単に。Laravel以外でも使えるよ。

npm run watch

関連ファイルを監視する
変更を感知すると自動的に再コンパイル

webpack.mix.jsファイル

Sass

saasメソッドはSassをCSSコンパイル

mix.sass('resources/assets/sass/app.scss', 'public/css');

ページを作ってみる

resource/js/app.js
/**
 * Next, we will create a fresh React component instance and attach it to
 * the page. Then, you may begin adding components to this application
 * or customize the JavaScript scaffolding to fit your unique needs.
 */

//require('./components/Example'); 
require('./components/index'); //ここを書き換える

次に、すべてのルーティングをindex.balde.phpに集中させる

web.php
Route::get('/{any}', function(){
    return view('index');
})->where('any', '.*'); 

bladeファイルを作成

index.blade.php
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
  <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="csrf-token" content="{{ csrf_token() }}">
  <title>Title</title>
</head>
<body>
<div id="root">
    {{-- <example-component></example-component> --}}
</div>

<script src="{{ asset('/js/app.js') }}"></script>
</body>
</html>

これでreact-router-domによるルーティングに対応できました。

参考:LaravelにReactを導入する時の手順〜ルーティングの設定

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

React Profiler onRenderコールバックの引数の要素のそれぞれに名前を付ける

render(
  <Profiler
    id="header"
    onRender={(...args) => {
      const argsObj = [
        "id",
        "phase",
        "actualDuration",
        "baseDuration",
        "startTime",
        "commitTime",
        "interactions"
      ].reduce((acc, cur, index) => ({ ...acc, [cur]: args[index] }), {});
      console.log(argsObj);
    }}
  >
    <Hoge />
  </Profiler>
);

// このような出力になる
{
  actualDuration: 0.07000000186963007
  baseDuration: 0.050000002374872565
  commitTime: 181.57500000233995
  id: "hoge"
  interactions: Set(0) {}
  phase: "mount"
  startTime: 178.71000000013737
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

React Material UI + Node.js expressのアプリ構築手順をまとめた

はじめに

フロントエンドがReact(Material UI)、バックエンドがNode.js expressのアプリを構築することがあったので、(何番煎じか分かりませんが)備忘録に手順を残します。

環境

  • Windows 10
  • Node.js v12.16.3
  • npm 6.14.4
  • yarn 1.22.4

手順

ディレクトリ作成

# アプリのコードを管理するディレクトリを作成
mkdir app
cd app
# クライアント、サーバーのコードを配置するディレクトリを作成
mkdir client server

フロントエンド:React, Material UI の導入

cd client
npx create-react-app my-app   ※my-app=アプリ名 ※npxはnpm 5.2 から利用できるパッケージランナーツール
cd my-app
yarn add @material-ui/core --save
# アプリ内でアイコンを使用したい場合はこれもインストールする。回線が遅いとインストール時にタイムアウトが発生する可能性があるため、タイムアウトの時間を長めに設定しておく。
yarn add @material-ui/icons --save  --network-timeout 1000000000

※動作確認は後ほど実施

バックエンド:express の導入

cd ../..
cd server
npm init (対話式で色々と入力するものがある。こだわりなければ全てEnterでよい。)
npm install express --save
type nul > server.js (macではtouch server.js かな? 単にsever.jsというファイルを作成しているだけ。)

server.jsをテキストエディタで開いて下記のコードをコピペする。

server.js
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');

const app = express();
app.use(bodyParser.json());
// Reactのアプリ名によってはディレクトリ名を一部変更する
app.use(express.static(path.join(__dirname, '../client/my-app/build')));

app.listen((process.env.PORT || 8000), () => {
  console.log(`Listening on port ${PORT}`);
});

動作確認

フロントエンド

  • 開発用サーバーの起動
cd client/my-app
yarn start

http://localhost:3000 にアクセスしてこのような画面が表示されれば成功です。
SnapCrab_NoName_2020-10-11_0-43-57_No-00.png

yarn start を実行中にApp.jsなどを変更して保存すると自動でコンパイルをしてページも自動でリロードされます。

フロントの開発中は yarn startで開発用サーバーを起動させつつ、バックエンドのexpressのサーバーも起動させてREST APIの呼び出しをするのが良いと思います。

  • ビルド

コードをビルドして、静的なファイル(html, jsファイルなど)を出力します。

yarn build

デフォルトでは app/client/my-app/build にビルドされたファイルが出力されます。
このフォルダをexpressのstaticフォルダとして設定しておくと、 http://localhost:8000 で表示することが出来ます。

バックエンド

  • サーバー起動
cd server
node server.js

http://localhost:8000 にアクセスして、http://localhost:3000 と同様の画面が表示されれば成功です。
SnapCrab_NoName_2020-10-11_0-43-33_No-00.png

おまけ

Material UIの Button component Icon componentを組み合わせた例です。
SnapCrab_NoName_2020-10-11_1-0-16_No-00.png

Material UIのIconの参照先: https://material.io/resources/icons/?icon=check_circle_outline&style=baseline

App.js
import React from 'react';
import './App.css';

import { Button } from '@material-ui/core';
import CheckCircleOutlineIcon from '@material-ui/icons/CheckCircleOutline';

function App() {
  return (
    <div className="App">
      <Button  variant="contained" color="primary">
        <CheckCircleOutlineIcon />
        please click!
      </Button>
    </div>
  );
}

export default App;
App.css
.App {
  padding-top: 100px;
  text-align: center;
}

参考サイト

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む