- 投稿日:2020-11-26T22:31:01+09:00
2020年React.js 最速マスターコース
Reactに難しいイメージが多いのか使える人を探しづらいという課題を感じています。
実際 Reactは長い歴史のなかで記述方法の変化、重要な機能が追加されつづけてきました。
そのすすんだ要素もふくめて、どうやって勉強するのがよいか、書いてみました。基本的には公式のチュートリアルをうまく組み合わせて勉強すればよいと思います。
step.0 環境準備
何はともあれ、node をインストールする必要があります。
node.js は頻発に バージョンアップがはいるため、nvm で管理しましょう。nvm
https://github.com/nvm-sh/nvm#installing-and-updating
nvm for windows の導入方法
https://docs.microsoft.com/ja-jp/windows/nodejs/setup-on-windows
Create React Appで勉強環境を構築
勉強をするためのアプリケーションを作れるようになりましょう。
Create React App は手軽に開発環境をつくれると同時に、
React開発のベストプラクティスがたくさんつめこまれています。https://ja.reactjs.org/docs/create-a-new-react-app.html
Typescript はこちら
https://create-react-app.dev/docs/adding-typescript/VSCodeの導入
https://code.visualstudio.com/
Step.1 React Tutorial の実施
まずは React の基本である State, Props, Event を下記のチュートリアルで体験しましょう。
https://ja.reactjs.org/tutorial/tutorial.htmlわからないところは公式ドキュメントやGoogleで調べながらすすめます。
Step.2 React Hooks
次に現代のスタンダードになりつつある React Hooksを学びましょう。
React Hooks
https://ja.reactjs.org/docs/hooks-overview.html概要を掴んだら、次は Step.1 のコードを React Hooks に書き直してみましょう。
その過程でわからなくったら公式ドキュメントを読みましょう。
終わる頃には半分ぐらいは理解できるようになっていると思います。Step.3
次は TypeScript です。
使うか使わないかはわかれると思いますが、スタンダードになりつつあります。TypeScript がはじめての人は下記をみてどうゆうものか把握します。5分で読めます。
英語なのでグーグル翻訳にかけると読みやすいです。https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html
大枠掴んだら、React でどう使うのかを下記で把握します。
Typescript の書き方はバージョンアップやユーザのアイディアにより日々進化します。
react-typescript-cheatsheetにそのグッドプラクティスが集まっています。
少し難しくてもこのサイトの内容で覚えtmoraeruReact Typescript
https://react-typescript-cheatsheet.netlify.app/docs/basic/setupStep.2 で作成した Hooks のアプリを TypeScript に書き換える
わからないところは react-typescript-cheatsheet を参考にしながらすすめます。
Step.4 Material UI
Material UI を学習します。
Material UI のサイトにはExampleが豊富にあり、使う際にそのコードをベースに改修することで導入できできます。Material UI のサンプルは JS, Typescript などのサンプルがあり、
どのサンプルもよいコードばかりです。css などの書き方も MaterialUIのコードがとても参考になると思います。
Step3 で作成したアプリを Material UI を使って便利にする。
その過程でMaterial UI のドキュメントやサンプルコードをたくさんみると思います。
そのなかでよりすすんだ書き方を習得できると思います。Next Step
- Redux
- Styled Components
- 投稿日:2020-11-26T22:31:01+09:00
2020年のReact.js を公式チュートリアルをもとにマスター
Reactに難しいイメージが多いのか使える人を探しづらいという課題を感じています。
実際 Reactは長い歴史のなかで記述方法の変化、重要な機能が追加されつづけてきました。
そのすすんだ要素もふくめて、どうやって勉強するのがよいか、書いてみました。基本的には公式のチュートリアルをうまく組み合わせて勉強すればよいと思います。
step.0 環境準備
何はともあれ、node をインストールする必要があります。
node.js は頻発に バージョンアップがはいるため、nvm で管理しましょう。nvm
https://github.com/nvm-sh/nvm#installing-and-updating
nvm for windows の導入方法
https://docs.microsoft.com/ja-jp/windows/nodejs/setup-on-windows
Create React Appで勉強環境を構築
勉強をするためのアプリケーションを作れるようになりましょう。
Create React App は手軽に開発環境をつくれると同時に、
React開発のベストプラクティスがたくさんつめこまれています。https://ja.reactjs.org/docs/create-a-new-react-app.html
Typescript はこちら
https://create-react-app.dev/docs/adding-typescript/VSCodeの導入
https://code.visualstudio.com/
Step.1 React Tutorial の実施
まずは React の基本である State, Props, Event を下記のチュートリアルで体験しましょう。
https://ja.reactjs.org/tutorial/tutorial.htmlわからないところは公式ドキュメントやGoogleで調べながらすすめます。
Step.2 React Hooks
次に現代のスタンダードになりつつある React Hooksを学びましょう。
React Hooks
https://ja.reactjs.org/docs/hooks-overview.html概要を掴んだら、次は Step.1 のコードを React Hooks に書き直してみましょう。
その過程でわからなくったら公式ドキュメントを読みましょう。
終わる頃には半分ぐらいは理解できるようになっていると思います。Step.3
次は TypeScript です。
使うか使わないかはわかれると思いますが、スタンダードになりつつあります。TypeScript がはじめての人は下記をみてどうゆうものか把握します。5分で読めます。
英語なのでグーグル翻訳にかけると読みやすいです。https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html
大枠掴んだら、React でどう使うのかを下記で把握します。
Typescript の書き方はバージョンアップやユーザのアイディアにより日々進化します。
react-typescript-cheatsheetにそのグッドプラクティスが集まっています。
少し難しくてもこのサイトの内容で覚えtmoraeruReact Typescript
https://react-typescript-cheatsheet.netlify.app/docs/basic/setupStep.2 で作成した Hooks のアプリを TypeScript に書き換える
わからないところは react-typescript-cheatsheet を参考にしながらすすめます。
Step.4 Material UI
Material UI を学習します。
Material UI のサイトにはExampleが豊富にあり、使う際にそのコードをベースに改修することで導入できできます。Material UI のサンプルは JS, Typescript などのサンプルがあり、
どのサンプルもよいコードばかりです。css などの書き方も MaterialUIのコードがとても参考になると思います。
Step3 で作成したアプリを Material UI を使って便利にする。
その過程でMaterial UI のドキュメントやサンプルコードをたくさんみると思います。
そのなかでよりすすんだ書き方を習得できると思います。Next Step
- Redux
- Styled Components
- 投稿日:2020-11-26T18:19:12+09:00
reactのaxiosでリクエスト失敗時の例外処理をいれる
- 投稿日:2020-11-26T16:40:34+09:00
React+Firebaseでゲストユーザーログイン機能を実装しよう!!
今回は、ボタンをクリックすると簡単にログインできる
ゲストログイン機能
を作成していきます。ポートフォリオなどを作る際に、評価していただく方がわざわざformに入力する必要がないように、ゲストログインボタンは作っておいて損はないと思います。
それでは見ていきましょう?
前提?♂️
- ReactとFirebaseでログイン機能を含むユーザー認証周りを作れるまたは既に完成している
- ゲストログインに関して大まかな実装の方法を知りたい場合
- 今回、firebaseの匿名認証は使いません
前提は上記の通りです。
FirebaseとReactでのログイン機能や会員登録機能についてわからないという場合は、以下のYouTube動画がおすすめです。
React Authentication Crash Course With Firebase And Routing
英語ではありますが、コードだけ見ていても多少は理解できると思います。
日本語解説については、
Firebase React 認証
などで検索すればいろいろ記事が出てきます。実装?
さて、早速実装していきます。
と言っても、ログインの機能を既に作成済みであればとても簡単です。
考え方としては、あらかじめgest userを作成しておき、ボタンをクリックしたときに自動的にそのguest userのemailとpasswordを使ってログインが行われるようにするという感じです。
guest userのemailは
guest@example.com
、パスワードはpassword
としてあらかじめアカウントを作成しておきます。
ログインの手段 違い 普通のログイン formにemailとpasswordを入力し、その値を使ってfirebaseのsignInWithEmailAndPasswordでログインする ゲストログイン ボタンをクリックしたら、ゲストログインの関数を実行させ、signInWithEmailAndPasswordに変数ではなく、直接guest@example.comとpasswordを渡す コードで説明した方がわかりやすいかもしれませんねw
hooksなどの定義やimport含め長くなりすぎるので省略しています。
Login.jsxexport default function Login() { const inputEmail = useCallback((event) => { setEmail(event.target.value) }, [setEmail]); const inputPassword = useCallback((event) => { setPassword(event.target.value) }, [setPassword]); //通常のログインの場合のログインボタンを押した後の処理 const handleSubmit = async(e) { e.preventDefault() setError("") setLoading(true) //login()の処理は別ファイルに記述しています。 //loginではsignInWithEmailAndPasswordでログイン処理をしています。 return login(email, password) .then(() => { history.push("/") }) .catch((error) => { setError("failed!!") }) .finally(() => { setLoading(false) }); } //以下ゲストログイン用の処理(ほぼ通常のログインと同じです) const onClickGuestButton = () => { setError("") setLoading(true) //loginの処理で直接emailとpasswordをloginに渡しています。 return login("guest@example.com", "password") .then(() => { history.push("/") }) .catch((error) => { setError("failed!!") }) .finally(() => { setLoading(false) }); } return( <> {/*ここにformのコードがあります*/} {/*ここからがゲストログインボタン。formの外に書いてます*/} <Button onClick={onClickGuestButton}> ゲストユーザーとしてログイン </Button> </> )以下は、loginの処理が書いてある
AuthContext.jsx
ですAuthContext.jsxconst login = (email, password) => { return auth.signInWithEmailAndPassword(email, password) }signInWithEmailAndPasswordはfirebaseのメソッドです。
これで実装完了です?
最後に?
いかがだったでしょうか?
ログイン機能を既に実装できているのであれば、ゲストログインボタンは結構簡単にできるものですよね。
作っておいて損はないです?♂️
もし、役に立ったと感じていただけたらLGTMお願いします!!?
- 投稿日:2020-11-26T15:52:23+09:00
Material-UIを使ってダイアログを表示するには?
Material-UIを使ってダイアログを表示するには一筋縄ではいかずパラメータを渡す必要があります。
なので今回は「Material-UIを使ってダイアログを表示する方法」を紹介します。この機能は3つのファイルで構成されています。
- 一覧画面(index.jsx)
- アイテムコンポーネント(item.jsx)
- ダイアログコンポーネント(dialog.jsx)
1.一覧画面
index.jsximport React from 'react'; import Box from '@material-ui/core/Box'; import Item from "@comp/item"; import Grid from '@material-ui/core/Grid'; import { makeStyles } from '@material-ui/core/styles'; const useStyles = makeStyles((theme) => ({ gridItem: { marginTop: theme.spacing(2), }, })); // 表示するアイテムのリスト const bookList = [ { id: 1, title: "ファスト&スロー", page: 100, image: "http://books.google.com/books/content?id=tNDza_Pb0UMC&printsec=frontcover&img=1&zoom=5&edge=curl&source=gbs_api" }, { id: 2, title: "ファストフードの恐ろしい話", page: 200, image: "http://books.google.com/books/content?id=ghgzDwAAQBAJ&printsec=frontcover&img=1&zoom=5&edge=curl&source=gbs_api" }, { id: 3, title: "英語でおもてなし・ファストフード食べ歩き", page: 300, image: "http://books.google.com/books/content?id=HC-gCAAAQBAJ&printsec=frontcover&img=1&zoom=5&edge=curl&source=gbs_api" }, ] export default function Index(props) { const classes = useStyles(); const compProps = { gridItem: { item : true, space : 5, xs : 12, md : 6, lg : 3, className : classes.gridItem } } return ( <> <Box mx={10} mt={4}> <Box display="flex" alignItems="center"> <h2>{props.title}</h2> </Box> <Grid container spacing={1}> {bookList.map(item => <Grid {...compProps.gridItem} key={item.id}> <Item bookParam={item} /> </Grid> )} </Grid> </Box> </> ); }一覧画面(
index.jsx
)では定義したリストを順番に並べて表示しています。まずは、表示するリストのデータを定義しています。通常はAPIやDBから取得したりしますが、今回は見本なので直接定義しています。
そして、定義したリストデータをループで回して各アイテムを
BookCard
というコンポーネントで表示しています。各データはbookParam
という名前でBookCard
コンポーネントに渡しています。2.アイテム
item.jsximport React, {useState} from 'react'; import Dialog from "@comp/dialog"; import Typography from '@material-ui/core/Typography'; import Box from '@material-ui/core/Box'; import Link from '@material-ui/core/Link'; const item = (props) => { /** 画面パラメータ */ const [dialogOpenF, setDialogOpenF] = useState(false); /** * コンポーネントに渡す引数 */ const compProps = { bookShowDialog: { open : dialogOpenF, //ダイアログの表示プローアティ bookParam: props.bookParam, onClose: () => setDialogOpenF(false), //ダイアログ非表示処理 }, showLink: { href: "#", onClick: () => setDialogOpenF(true) //ダイアログ表示処理 } } return ( <Box> {/* 画像の表示 */} <Link {...compProps.showLink}> <img src={props.bookParam.image}/> </Link> {/* タイトルの表示 */} <Typography> <Link {...compProps.showLink}> {props.bookParam.title} </Link> </Typography> {/* ページ数の表示 */} <Typography>{props.bookParam.page}ページ</Typography> {/* ダイアログの表示 */} <Dialog {...compProps.bookShowDialog} /> </Box> ); } export default item;各アイテム(
item.jsx
)では呼び出し元から渡されたデータの表示とダイアログの表示・非表示の処理を行っています。引き渡されたパラメータは
props.bookParam
に格納されているため画像URL(image
)、タイトル(title
)、ページ数(page
)をそのまま出力に利用しています。そして、最後の
Dialog
コンポーネントに各アイテムの情報を渡しています。2-1.ダイアログの表示・非表示
ダイアログ表示・非表示用のパラメータ
dialogOpenF
を用意しています。このパラメータをtrue・falseに更新することでダイアログの表示・非表示に切り替えているわけです。後は画像とタイトルがクリックされたときに
dialogOpenF
を更新するメソッドsetDialogOpenF
を使ってtrueに変更しています。これによりopen
プロパティーが更新されダイアログが表示されます。そして、ダイアログが閉じる処理を行ったときに
setDialogOpenF
でfalseを指定してダイアログを非表示に更新しています。3.ダイアログ
dialog.jsximport React from 'react'; import Button from '@material-ui/core/Button'; import Dialog from '@material-ui/core/Dialog'; import DialogActions from '@material-ui/core/DialogActions'; import DialogContent from '@material-ui/core/DialogContent'; import DialogContentText from '@material-ui/core/DialogContentText'; import DialogTitle from '@material-ui/core/DialogTitle'; import PropTypes from 'prop-types'; import Typography from '@material-ui/core/Typography'; const dialog = (props) => { const compProps = { dialog: { open: props.open, //ダイアログの表示・非表示プロパティ onClose: props.onClose, //ダイアログが閉じられた時の処理 scroll:'paper', }, dialogContent: { dividers: true }, dialogContentText: { tabIndex: -1 }, closeButton: { onClick: props.onClose, //閉じるボタンが押されたときの処理 color: "primary" }, } return ( <Dialog {...compProps.dialog}> {/* タイトル */} <DialogTitle>{props.bookParam.title}</DialogTitle> {/* 画像とページ数 */} <DialogContent {...compProps.dialogContent}> <img src={props.bookParam.image} /> <DialogContentText {...compProps.dialogContentText}> <Typography>{props.bookParam.page}ページ</Typography> </DialogContentText> </DialogContent> {/* 閉じるボタン */} <DialogActions> <Button {...compProps.closeButton}> 閉じる </Button> </DialogActions> </Dialog> ); } dialog.propTypes = { open: PropTypes.bool, //表示フラグ onClose: PropTypes.func, //閉じる処理 } export default dialog;最後にダイアログに呼び出し元から渡された情報を出力します。
DialogTitle
にはアイテムのタイトル。DialogContent
にはアイテムの画像とページ数を表示。そして、ダイアログを閉じる処理を行う「閉じるボタン」を定義します。閉じるボタンが押されたときは呼び出し元から引き渡された
props.onClose
を利用します。これにより、呼び出し元からダイアログを非表示にします。また、
propTypes
で呼び出し元からのパラメータの型をチェックしまています。open
はダイアログの表示・非表示でboolean型。onClose
は閉じる処理でfunc型。これにより異常な値が渡ってこれば警告が表示されるようになっているのです。
- 投稿日:2020-11-26T15:20:12+09:00
キャッシュとクッキーの違い(メモ)
共通点と違い
- 共通点
- どちらもブラウザ訪問後に情報を一時的に保存することができる。
- 違い
- 保存する情報の内容が違う
それぞれの特徴
- キャッシュ
- 訪れたウェブページの情報を一時的に保存する。 これにより訪れるページの読み込みが速くなる。
- クッキー
- ページに訪れたユーザーの情報を一時的に保存する。 例えば、一度パスワードを打ってログインしたサイトに再度訪れてもログイン状態になっているのはクッキーのおかげ。
キャッシュのデメリットを覚えておこう
- ウェブページの最新情報反映について。キャッシュデータはキャッシュした時点のデータなのでウェブページの更新があっても最新のものに切り替わらないため一度古いキャッシュを削除する必要がある。
- キャッシュによってPCやスマホの容量が食われてしまうことがあるので注意が必要。
参考記事
https://time-space.kddi.com/ict-keywords/20191210/2798
余談
react native でsimulatorを使いながら開発を進めていた際に、何度かキャッシュを削除することでエラーが直ることがありました。
- 投稿日:2020-11-26T14:53:53+09:00
React-leafletの使い方メモ
React-leafletとは
Open Source Mapを表示するJavaScriptライブラリであるleafletを、React.js上で使えるように拡張するライブラリです。
React Leaflet公式
https://react-leaflet.js.org/本記事は公式のチュートリアルを順番にやっていくだけですので詳しくは公式サイトを参照してください
https://react-leaflet.js.org/docs/start-introduction1. プロジェクトの作成
terminalmkdir react-leaflet cd react-leaflet npx create-react-app my-app
2. インストール
今回は開発版をインストールしました
開発版をインストールする場合npm install leaflet react-leaflet@next --save
安定版をインストールする場合npm install leaflet react-leaflet --save
3. 地図を表示
こちらのコードを参考にやっていきます
https://qiita.com/sugasaki/items/d225cf548e9a787dbd9c地図を表示する為のクラスを作成
MapContainerで地図オブジェクトをつくり、TileLayerで地図タイルを取得できるようにすると地図が表示されます。
MapContainerがL.map()、TileLayerがL.tileLayer()、MarkerがL.marker()に対応していますので、leaflet触ったことがある方はイメージしやすいと思います。
my-app/component/simple.jsimport React, { Component } from 'react' import { MapContainer, TileLayer, Marker, Popup } from 'react-leaflet' export default class SimpleExample extends Component { render() { const position = [51.505, -0.09]; return ( <MapContainer center={position} zoom={13} scrollWheelZoom={false}> <TileLayer attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors' url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" /> <Marker position={position}> <Popup> A pretty CSS3 popup. <br /> Easily customizable. </Popup> </Marker> </MapContainer> ) } }App.jsでSimpleExampleクラスを呼ぶように変更
my-app/App.jsimport Leaflet from 'leaflet' import React, { Component } from 'react'; import './App.css'; import 'leaflet/dist/leaflet.css'; import SimpleExample from './components/simple' Leaflet.Icon.Default.imagePath = '//cdnjs.cloudflare.com/ajax/libs/leaflet/1.3.1/images/' class App extends Component { render() { return ( <SimpleExample /> ); } } export default App;leafletコンテナの表示幅を指定
指定し忘れると高さゼロ(=表示されない)になってしまうので必ず設定します
my-app/index.js.leaflet-container { width: 600px; height: 300px; margin: 10px;サーバーを起動して確認
サーバーを起動します
terminalnpm start
以上でhttp://localhost:3000/ に地図が表示される筈です
4. イベント管理
useMapEvents()によりleafletのイベントハンドラを使うことができます。以下ではclick()イベントが発生したら端末の現在位置を取得してMarkerを置くという動作を追加しています。
my-app/components/event.jsimport React, { Component, useState } from 'react' import { MapContainer, TileLayer, useMapEvents, Marker, Popup } from 'react-leaflet' function LocationMarker() { const [position, setPosition] = useState(null) const map = useMapEvents({ click() { map.locate() }, locationfound(e) { setPosition(e.latlng) map.flyTo(e.latlng, map.getZoom()) }, }) return position === null ? null : ( <Marker position={position}> <Popup>You are here</Popup> </Marker> ) } export default class EventsExample extends Component { render() { const position = [51.505, -0.09]; return ( <MapContainer center={position} zoom={13} scrollWheelZoom={false}> <TileLayer attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors' url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" /> <LocationMarker /> </MapContainer> ) } }my-app/App.jsimport Leaflet from 'leaflet' import React, { Component } from 'react'; import './App.css'; import 'leaflet/dist/leaflet.css'; import SimpleExample from './components/simple' import EventsExample from './components/events' Leaflet.Icon.Default.imagePath = '//cdnjs.cloudflare.com/ajax/libs/leaflet/1.3.1/images/' class App extends Component { render() { return ( <div> SimpleExample <SimpleExample /> EventsExample <EventsExample /> </div> ); } } export default App;5. ポリゴンを表示
ポリゴンも簡単に追加できます
my-app/src/components/polygon.jsimport React, { Component } from 'react' import { MapContainer, TileLayer, Popup, Circle, CircleMarker, Polyline, Polygon, Rectangle } from 'react-leaflet' export default class PolygonExample extends Component { render() { const center = [51.505, -0.09]; const polyline = [ [51.505, -0.09], [51.51, -0.1], [51.51, -0.12], ]; const multiPolyline = [ [ [51.5, -0.1], [51.5, -0.12], [51.52, -0.12], ], [ [51.5, -0.05], [51.5, -0.06], [51.52, -0.06], ], ]; const polygon = [ [51.515, -0.09], [51.52, -0.1], [51.52, -0.12], ]; const multiPolygon = [ [ [51.51, -0.12], [51.51, -0.13], [51.53, -0.13], ], [ [51.51, -0.05], [51.51, -0.07], [51.53, -0.07], ], ]; const rectangle = [ [51.49, -0.08], [51.5, -0.06], ]; const fillBlueOptions = { fillColor: 'blue' }; const blackOptions = { color: 'black' }; const limeOptions = { color: 'lime' }; const purpleOptions = { color: 'purple' }; const redOptions = { color: 'red' }; return ( <MapContainer center={center} zoom={13} scrollWheelZoom={false}> <TileLayer attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors' url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" /> <Circle center={center} pathOptions={fillBlueOptions} radius={200} /> <CircleMarker center={[51.51, -0.12]} pathOptions={redOptions} radius={20}> <Popup>Popup in CircleMarker</Popup> </CircleMarker> <Polyline pathOptions={limeOptions} positions={polyline} /> <Polyline pathOptions={limeOptions} positions={multiPolyline} /> <Polygon pathOptions={purpleOptions} positions={polygon} /> <Polygon pathOptions={purpleOptions} positions={multiPolygon} /> <Rectangle bounds={rectangle} pathOptions={blackOptions} /> </MapContainer> ) } }6. SVG overlay
SVGを上に重ねることもできます
my-app/src/components/svg.jsimport React, { Component } from 'react' import { MapContainer, TileLayer, SVGOverlay } from 'react-leaflet' export default class SVGExample extends Component { render() { const position = [51.505, -0.09]; const bounds = [ [51.49, -0.08], [51.5, -0.06], ]; return ( <MapContainer center={position} zoom={13} scrollWheelZoom={false}> <TileLayer attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors' url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" /> <SVGOverlay attributes={{ stroke: 'red' }} bounds={bounds}> <rect x="0" y="0" width="100%" height="100%" fill="blue" /> <circle r="5" cx="10" cy="10" fill="red" /> <text x="50%" y="50%" stroke="white"> text </text> </SVGOverlay> </MapContainer> ) } }7. LayerGroupとFeatureGroup
leafletにあるLayerGroupとかFeatureGroupも使えます
my-app/src/components/group.jsimport React, { Component } from 'react' import { MapContainer, TileLayer, Popup, LayerGroup, Circle, FeatureGroup, Rectangle } from 'react-leaflet' export default class LayerGroupExample extends Component { render() { const center = [51.505, -0.09]; const rectangle = [ [51.49, -0.08], [51.5, -0.06], ]; const fillBlueOptions = { fillColor: 'blue' }; const fillRedOptions = { fillColor: 'red' }; const greenOptions = { color: 'green', fillColor: 'green' }; const purpleOptions = { color: 'purple' }; return ( <MapContainer center={center} zoom={13} scrollWheelZoom={false}> <TileLayer attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors' url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" /> <LayerGroup> <Circle center={center} pathOptions={fillBlueOptions} radius={200} /> <Circle center={center} pathOptions={fillRedOptions} radius={100} stroke={false} /> <LayerGroup> <Circle center={[51.51, -0.08]} pathOptions={greenOptions} radius={100} /> </LayerGroup> </LayerGroup> <FeatureGroup pathOptions={purpleOptions}> <Popup>Popup in FeatureGroup</Popup> <Circle center={[51.51, -0.06]} radius={200} /> <Rectangle bounds={rectangle} /> </FeatureGroup> </MapContainer> ) } }8. マウスオーバーで注釈を出す
MarkerやCircleにTooltipを追加しておくと注釈を出すことが出来ます
my-app/src/components/tooltips.jsimport React, { Component } from 'react' import { MapContainer, TileLayer, Marker, Popup, Circle, CircleMarker, Polygon, Rectangle, Tooltip } from 'react-leaflet' import { useState, useMemo } from 'react' const center = [51.505, -0.09] const multiPolygon = [ [ [51.51, -0.12], [51.51, -0.13], [51.53, -0.13], ], [ [51.51, -0.05], [51.51, -0.07], [51.53, -0.07], ], ]; const rectangle = [ [51.49, -0.08], [51.5, -0.06], ]; function TooltipCircle() { const [clickedCount, setClickedCount] = useState(0) const eventHandlers = useMemo( () => ({ click() { setClickedCount((count) => count + 1) }, }), [], ) const clickedText = clickedCount === 0 ? 'Click this Circle to change the Tooltip text' : `Circle click: ${clickedCount}` return ( <Circle center={center} eventHandlers={eventHandlers} pathOptions={{ fillColor: 'blue' }} radius={200}> <Tooltip>{clickedText}</Tooltip> </Circle> ) } export default class ToolTipsExample extends Component { render() { return ( <MapContainer center={center} zoom={13} scrollWheelZoom={false}> <TileLayer attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors' url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" /> <TooltipCircle /> <CircleMarker center={[51.51, -0.12]} pathOptions={{ color: 'red' }} radius={20}> <Tooltip>Tooltip for CircleMarker</Tooltip> </CircleMarker> <Marker position={[51.51, -0.09]}> <Popup>Popup for Marker</Popup> <Tooltip>Tooltip for Marker</Tooltip> </Marker> <Polygon pathOptions={{ color: 'purple' }} positions={multiPolygon}> <Tooltip sticky>sticky Tooltip for Polygon</Tooltip> </Polygon> <Rectangle bounds={rectangle} pathOptions={{ color: 'black' }}> <Tooltip direction="bottom" offset={[0, 20]} opacity={1} permanent> permanent Tooltip for Rectangle </Tooltip> </Rectangle> </MapContainer> ) } }9. LayersControl
レイヤーを選んで表示するようにすることもできます
my-app/src/components/leyersControl.jsimport React, { Component } from 'react' import { MapContainer, TileLayer, Marker, Popup, LayersControl, LayerGroup, Circle, FeatureGroup, Rectangle } from 'react-leaflet' export default class LayersControlExample extends Component { render() { const center = [51.505, -0.09]; const rectangle = [ [51.49, -0.08], [51.5, -0.06], ]; return ( <MapContainer center={center} zoom={13} scrollWheelZoom={false}> <LayersControl position="topright"> <LayersControl.BaseLayer checked name="OpenStreetMap.Mapnik"> <TileLayer attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors' url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" /> </LayersControl.BaseLayer> <LayersControl.BaseLayer name="OpenStreetMap.BlackAndWhite"> <TileLayer attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors' url="https://tiles.wmflabs.org/bw-mapnik/{z}/{x}/{y}.png" /> </LayersControl.BaseLayer> <LayersControl.Overlay name="Marker with popup"> <Marker position={center}> <Popup> A pretty CSS3 popup. <br /> Easily customizable. </Popup> </Marker> </LayersControl.Overlay> <LayersControl.Overlay checked name="Layer group with circles"> <LayerGroup> <Circle center={center} pathOptions={{ fillColor: 'blue' }} radius={200} /> <Circle center={center} pathOptions={{ fillColor: 'red' }} radius={100} stroke={false} /> <LayerGroup> <Circle center={[51.51, -0.08]} pathOptions={{ color: 'green', fillColor: 'green' }} radius={100} /> </LayerGroup> </LayerGroup> </LayersControl.Overlay> <LayersControl.Overlay name="Feature group"> <FeatureGroup pathOptions={{ color: 'purple' }}> <Popup>Popup in FeatureGroup</Popup> <Circle center={[51.51, -0.06]} radius={200} /> <Rectangle bounds={rectangle} /> </FeatureGroup> </LayersControl.Overlay> </LayersControl> </MapContainer> ) } }10. stateの値でRectangleの色を変える
この辺からleaflet単独ではなくReactからleafletを操作する手順になります。ここではEffectフックでRectangleの色を変えています。
my-app/src/components/panes.jsimport React, { Component, useState, useRef, useEffect } from 'react' import { MapContainer, TileLayer, Pane, Rectangle } from 'react-leaflet' const outer = [ [50.505, -29.09], [52.505, 29.09], ] const inner = [ [49.505, -2.09], [53.505, 2.09], ] function BlinkingPane() { const [render, setRender] = useState(true) const timerRef = useRef() useEffect(() => { timerRef.current = setInterval(() => { setRender((r) => !r) }, 1000) return () => { clearInterval(timerRef.current) } }, []) return render ? ( <Pane name="cyan-rectangle" style={{ zIndex: 500 }}> <Rectangle bounds={outer} pathOptions={{ color: 'cyan' }} /> </Pane> ) : null } export default class PanesExample extends Component { render() { return ( <MapContainer bounds={outer} scrollWheelZoom={false}> <TileLayer attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors' url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" /> <BlinkingPane /> <Pane name="yellow-rectangle" style={{ zIndex: 499 }}> <Rectangle bounds={inner} pathOptions={{ color: 'yellow' }} /> <Pane name="purple-rectangle"> <Rectangle bounds={outer} pathOptions={{ color: 'purple' }} /> </Pane> </Pane> </MapContainer> ) } }横に長いRectangleが紫⇔青と交互に色を変えながら表示されます
11. Drag可能なMarker
MarkerをDraggableにするかどうかをReact stateにしておいて、途中でDrag可能にしたりDragできなくしたりする例です
my-app/src/components/draggable.jsimport React, { Component, useState, useRef, useMemo, useCallback } from 'react' import { MapContainer, TileLayer, Marker, Popup } from 'react-leaflet' const center = { lat: 51.505, lng: -0.09, } function DraggableMarker() { const [draggable, setDraggable] = useState(false) const [position, setPosition] = useState(center) const markerRef = useRef(null) const eventHandlers = useMemo( () => ({ dragend() { const marker = markerRef.current if (marker != null) { setPosition(marker.getLatLng()) } }, }), [], ) const toggleDraggable = useCallback(() => { setDraggable((d) => !d) }, []) return ( <Marker draggable={draggable} eventHandlers={eventHandlers} position={position} ref={markerRef}> <Popup minWidth={90}> <span onClick={toggleDraggable}> {draggable ? 'Marker is draggable' : 'Click here to make marker draggable'} </span> </Popup> </Marker> ) } export default class DraggableMarkerExample extends Component { render() { return ( <MapContainer center={center} zoom={13} scrollWheelZoom={false}> <TileLayer attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors' url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" /> <DraggableMarker /> </MapContainer> ) } }12. View Bounds
innerBoundsまたはouterBoundsの内側をクリックすると、クリックした側をinnerHandler、クリックしていない側をouterHandlerに登録して、その範囲が大きく表示されるように
my-app/src/components/viewBounds.jsimport React, { Component, useState, useMemo } from 'react' import { MapContainer, TileLayer, Rectangle, useMap } from 'react-leaflet' const innerBounds = [ [49.505, -2.09], [53.505, 2.09], ] const outerBounds = [ [50.505, -29.09], [52.505, 29.09], ] const redColor = { color: 'red' } const whiteColor = { color: 'white' } function SetBoundsRectangles() { const [bounds, setBounds] = useState(outerBounds) const map = useMap() const innerHandlers = useMemo( () => ({ click() { setBounds(innerBounds) map.fitBounds(innerBounds) }, }), [map], ) const outerHandlers = useMemo( () => ({ click() { setBounds(outerBounds) map.fitBounds(outerBounds) }, }), [map], ) return ( <> <Rectangle bounds={outerBounds} eventHandlers={outerHandlers} pathOptions={bounds === outerBounds ? redColor : whiteColor} /> <Rectangle bounds={innerBounds} eventHandlers={innerHandlers} pathOptions={bounds === innerBounds ? redColor : whiteColor} /> </> ) } export default class ViewBoundsExample extends Component { render() { return ( <MapContainer bounds={outerBounds} scrollWheelZoom={false}> <TileLayer attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors' url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" /> <SetBoundsRectangles /> </MapContainer> ) } }13. Animated Panning
checkboxの値でsetViewのanimateを有効にしたり無効にしたりできます
my-app/src/components/animatedPanning.jsimport React, { Component, useRef } from 'react' import { MapContainer, TileLayer, useMapEvent } from 'react-leaflet' function SetViewOnClick({ animateRef }) { const map = useMapEvent('click', (e) => { map.setView(e.latlng, map.getZoom(), { animate: animateRef.current || false, }) }) return null } function AnimateExample() { const animateRef = useRef(false) return ( <> <p> <label> <input type="checkbox" onChange={() => { animateRef.current = !animateRef.current }} /> Animate panning </label> </p> <MapContainer center={[51.505, -0.09]} zoom={13} scrollWheelZoom={false}> <TileLayer attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors' url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" /> <SetViewOnClick animateRef={animateRef} /> </MapContainer> </> ) } export default class AnimatedPanningExample extends Component { render() { return ( <AnimateExample /> ) } }14. External State
逆にleafletの情報をコンポーネント外で使うことも出来ます
my-app/src/components/import React, {useState, useCallback, useEffect, useMemo} from 'react' import { MapContainer, TileLayer } from 'react-leaflet' const center = [51.505, -0.09] const zoom = 13 function DisplayPosition({ map }) { const [position, setPosition] = useState(map.getCenter()) const onClick = useCallback(() => { map.setView(center, zoom) }, [map]) const onMove = useCallback(() => { setPosition(map.getCenter()) }, [map]) useEffect(() => { map.on('move', onMove) return () => { map.off('move', onMove) } }, [map, onMove]) return ( <p> latitude: {position.lat.toFixed(4)}, longitude: {position.lng.toFixed(4)}{' '} <button onClick={onClick}>reset</button> </p> ) } function ExternalStateExample() { const [map, setMap] = useState(null) const displayMap = useMemo( () => ( <MapContainer center={center} zoom={zoom} scrollWheelZoom={false} whenCreated={setMap}> <TileLayer attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors' url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" /> </MapContainer> ), [], ) return ( <div> {map ? <DisplayPosition map={map} /> : null} {displayMap} </div> ) } export default ExternalStateExample;まとめ
Reactを使う環境でleafletを使うなら単独で使うよりこちらを使った方が良さげです
- 投稿日:2020-11-26T11:47:09+09:00
React躓きメモ
Async callback was not invoked within the 5000ms timeout specified by jest.setTimeoutでjestのテストが上手くいかないケース
it("テストネーム", async () => { // settimeoutを繰り返すようなテスト }, 時間);上記のように、itの第3引数に時間を入れることで上手くいくらしい
useEffectがstateなどで何度もレンダリングされてしまう。
https://qiita.com/k-penguin-sato/items/9373d87c57da3b74a9e
以下のように第2引数をから配列にすればいいらしい。
useEffect(() => {
// 処理
}, []);
- 投稿日:2020-11-26T01:19:59+09:00
静的サイトジェネレーター Gatsby.js 入門
Gatsby.js入門
第1回は、Gatsby.jsのインストールの仕方について書いていこうと思います
Gatsby.jsを利用するための準備
開発環境の用意
・Node.js(nvm)
・yarn
・gitのインストールが必要です
インストールの仕方については、次の記事を参照してくださいGatsby CLIをインストールする
yarn global add gatsby-cli
と入力して、Gatsby.jsをインストールしていきます。スターターをダウンロードしてみる
gatsby new
と入力して、サイトを構築していきます。入力すると、プロジェクト名と使用するスターターを聞いてくるので、自分にあったプロジェクト名とスターターを選んであげましょう。
※スターターについては、https://www.gatsbyjs.org/starters/?v=2
を参照してみてくださいダウンロードできたら、
cd プロジェクト名
でプロジェクトフォルダに移動し、gatsby develop
で開発サーバーを起動してみます。開発サーバーが起動したら、URLからページに飛んでページの表示を確認してみましょう!
サイトを公開する
gatsby build
と入力するとpublic/フォルダにサイトのデータができあがります。
これを公開すればサイトの公開は完了です。※ちなみにビルドしたサイトの表示を確認する場合、
gatsby serve
と入力するば、ビルドしたサイトを確認することが可能です。参考文献:Webサイト高速化のための静的サイトジェネレーター活用入門 GatsbyJSで実現する高速&実用的なサイト構築