20211008のReactに関する記事は8件です。

React Study(3) ~ 世界時計を作ってみよう

世界時計を作る  ここまでサンプルプログラムを動かすようなことだけやってきたので、今ある知識で作れそうなものをとりあえず一つ作ってみましょう。  ドロップダウンがあってそこでタイムゾーンを選ぶと、そのタイムゾーンの時計が表示され、秒を刻むシンプルな世界時計を作ってみます。 プロジェクト作成  まずはcreate-react-appでベースを作ります。コマンドぽちでしばし待機。 create-react-app c:\projects>npx create-react-app react_watch (省略) We suggest that you begin by typing: cd react_watch npm start Happy hacking! c:\projects>  ここまではほぼテンプレ。ここからsrc/App.jsをいじります。本当はちゃんとコンポーネント化したほうがいいよ、ってのをよく見るのですが、とりあえずApp.jsに全部書いちゃいます。 画面の構成  完成系はこんな感じです。スタイルも何もなく非常にそっけない画面ですが気にしません。 現在時刻 タイムゾーン タイムゾーンのセレクタ  パーツはこれだけになります。動きとしてはタイムゾーンのセレクタを動かすとそのタイムゾーンの時間を表示してくれる。これだけです。 画面パーツ  最初に画面パーツ用の部品を用意します。と、言ってもセレクタ用のoptionの配列と、いくら何でもマージンのない画面も。。。ということで申し訳程度のstyleです。 App.js const WatchComponent = () => { // 時間 const date = new Date(); // 最低限のスタイル… const style = { margin:"10pt" }; // 選択できるタイムゾーン const timeZones = [ {id:1, zone:"Asia/Tokyo"}, {id:2, zone:"Europe/London"}, {id:3, zone:"America/New_York"} ]; // タイムゾーンをoptionタグに変換しておく const SelectItems = timeZones.map((item)=>{ return ( <option value={item.zone} key={item.id}>{item.zone}</option> ) });  後から好きにタイムゾーンを増やせるようにoptionタグをべた書きせずに配列に入れて、map関数でばらしてoptionタグに変換しています。 状態の保存  状態は選ばれているタイムゾーン、今の時間。この2つです。 App.js // 初期は日本時間 const [selectedTimeZone, setTimeZone] = useState(timeZones[0].zone); // 初期表示は日本時間の今 const [dispTime, setTime] = useState(date.toLocaleString('en-US',{ timeZone: selectedTimeZone })); // selectが選択された時の挙動 const handleChange = (e) => { // タイムゾーンを選択されたものにする setTimeZone(e.target.value); };  useStateを使って2つの状態を宣言します。それぞれselectedTimeZone、dispTimeです。  セレクタが選択された時にタイムゾーンを設定しなおすhandlerも宣言しておきます。 1秒ごとに画面を更新  さて、時計アプリなので毎秒画面を更新したいので、useEffectからsetIntervalでタイマーを作ります。クリーンアップ関数でそのタイマーを削除する処理も忘れずに。 App.js const callbackFunction = () =>{ // 1000ミリ秒ごとにsetTimeしなおす const timer = setInterval( () => { setTime(new Date().toLocaleString('en-US',{ timeZone: selectedTimeZone })); } ,1000); return () => { clearInterval(timer); }; }; // 時間・タイムゾーンに変更があったら呼び出し useEffect(callbackFunction,[selectedTimeZone,dispTime]);  タイムゾーンが変更されたり、表示時間が変わったたらまた1秒待って再描画…を繰り返しています。毎秒callbackFunctionを作り直してる動きになるのかな?ここのパフォーマンスをよくするにはuseCallbackを使うようですが、それはおいおい… 時計の表示  これでパーツはそろったのであとは表示だけ。 App.js return ( <> <div style={style}> <div>{dispTime}</div> <div>{selectedTimeZone}</div> <select value={selectedTimeZone} onChange={handleChange}> {SelectItems} </select> </div> </> ); これで無事、時計が表示されました。 ソース全体  ソース全体を貼り付けます。正直React云々じゃなくてJavascriptとして修正すべき点が多い気がしますが、学習数日でこの少ないコード量でインタラクティブなページが簡単にできるのはReactの力かなぁと感じました。 App.js import React, {useState,useEffect} from "react"; const WatchComponent = () => { // 時間 const date = new Date(); // 最低限のスタイル… const style = { margin:"10pt" }; // 選択できるタイムゾーン const timeZones = [ {id:1, zone:"Asia/Tokyo"}, {id:2, zone:"Europe/London"}, {id:3, zone:"America/New_York"} ]; // タイムゾーンをoptionタグに変換しておく const SelectItems = timeZones.map((item)=>{ return ( <option value={item.zone} key={item.id}>{item.zone}</option> ) }); // 初期は日本時間 const [selectedTimeZone, setTimeZone] = useState(timeZones[0].zone); // 初期表示は日本時間の今 const [dispTime, setTime] = useState(date.toLocaleString('en-US',{ timeZone: selectedTimeZone })); // selectが選択された時の挙動 const handleChange = (e) => { // タイムゾーンを選択されたものにする setTimeZone(e.target.value); }; const callbackFunction = () =>{ // 1000ミリ秒ごとにsetTimeしなおす const timer = setInterval( () => { setTime(new Date().toLocaleString('en-US',{ timeZone: selectedTimeZone })); } ,1000); return () => { clearInterval(timer); }; }; // 時間・タイムゾーンに変更があったら呼び出し useEffect(callbackFunction,[selectedTimeZone,dispTime]); return ( <> <div style={style}> <div>{dispTime}</div> <div>{selectedTimeZone}</div> <select value={selectedTimeZone} onChange={handleChange}> {SelectItems} </select> </div> </> ); }; export default function App() { return <WatchComponent />; }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

React Server Components で #STUDY WITH ME のサービスを作ってみた

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

React ステートフック

ステートフックとは ステートのためのフック。 ステートとは、値をコンポーネント内で保持しその値を更新すると表示が更新できる。 ただし、クラスコンポーネントでしか使えない。 ステートフックは関数コンポーネントでもステート機能を使えるようにしたもの。 ステートフックの作り方・呼び出し方 export default function(){ const [変数A,変数B] = useState(初期値); const 関数C = ()=>{ 変数B() //変数Bの内容は変数Aを更新する処理 } return( <div onClick={関数C}> {変数A} </div> ) } 変数Aはステートの値。呼び出すときに使う。 変数Bはステートの値を変更する関数 呼び出すだけで、変更が必要ない場合は変数B、関数Cはいらない。 更新する場合は、イベント時に関数Cを呼び出すなどします。関数Cが実行されると、変数Bが実行され、変数Aの値が更新されます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Reactアプリケーションを作成してAWS Amplifyサービスにホスティングする

はじめに Reactでアプリケーションを作成してAWS Amplifyサービスを使ってホスティングしてみようと思います。 gitリポジトリ作成 1) 「New repository」をクリックします 2) git ripository作成に必要な項目を入力してcreate repositoryをクリックします Repository name:任意の名前 公開設定: privateを選択 Reactアプリケーションの作成 3) npxのバージョンを確認 $ npx --version 6.14.15 npxがインストールされていない場合 $ npm install -g npx 4) creat-react-appのインストール $ npx create-react-app --template typescript react-test 5) 起動させてみる $ cd react-test $ npm start 以下のURLにアクセスする localhost3000 reactアプリをpush 6) 以下のコマンドを実行してpushします $ git init $ git add . $ git commit -m "first commit" $ git branch -M master # 以下のコマンドにgit urlを追加します $ git remote add origin --- [git url] --- $ git push origin master AWS Amplifyの設定 7) マネージメントコンソールにログインしてAWS Amplifyサービスを開いて「Deliver」の「Get started」をクリックします マネージメントコンソール 8) 「GitHub」を選択して「Continue」をクリックします 9) リポジトリブランチの追加に必要な項目を選択して「次へ」をクリックします リポジトリ:先ほどgithubで作成したリポジトリを選択 ブランチ: reactアプリをpushしたブランチを選択 10) ビルド設定の構成が表示されるので「次へ」をクリックします 11) 「保存してデプロイ」をクリックします 動作確認 12) しばらくすると「プロビジョン」~ 「検証」まで✅がつくので、「全般」をクリックして「本番用ブランチURL」のURLをクリックして動作確認します クリックしたURLでアクセスできること確認できました 更新してみる 13) プログラムを更新してgitにpushする src/App.tsxを編集してみる 11行目を削除して「hello world」に変更 App.tsx import React from 'react'; import logo from './logo.svg'; import './App.css'; function App() { return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <p> hell world {/* 変更 */} </p> <a className="App-link" href="https://reactjs.org" target="_blank" rel="noopener noreferrer" > Learn React </a> </header> </div> ); } export default App; 14) pushして更新する $ git add App.tsx $ git commit -m "two commit" $ git push origin master 15) AWS Amplifyを開いて「react-test」(Amplifyを作成した名前)をクリックして「検証」をクリックします 16) 「このバージョンを再デプロイ」をクリックしてしばらくすると再度「プロビジョン」~「検証」まで✅がついたら「ドメイン」のURLをクリックします 更新されてることが確認できました
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

react-burger-menuとはなんなのか

はじめに Next.jsの開発でバーガーメニュー作りたいなと思って調べたら react-burger-menuというもので簡単にバーガーメニューが作れるようなので紹介します。 使い方 一応公式のREADME置いときます。 https://github.com/negomi/react-burger-menu 1. インストール(Installation) 以下のコマンドでインストールを行う npm install react-burger-menu --save or yarn add react-burger-menu TypeScriptを使っている方は以下のコマンドでインストール npm install @types/react-burger-menu --save or yarn add @types/react-burger-menu 2. 利用方法(Usage) アニメーション(animation)について react-burger-menuでは以下のようなアニメーションを選択できます。 ・slide ・stack ・elastic ・bubble ・push ・pushRotate ・scaleDown ・scaleRotate ・fallDown ・reveal 実際のアニメーションは公式が出しているサイトで見れます。 (https://negomi.github.io/react-burger-menu/) 使用する際は, ファイル内で以下のようにimportします。 import { slide as Menu } from 'react-burger-menu' この時, slide以外のアニメーションを使いたい場合は上で記述したアニメーションに適宜書き換えれば変更することができます。 プロパティ(Properties)について Page wrapper ページの残りをラップする要素は以下のようにMenuコンポーネントの後に配置し, idを一致させる。 <Menu pageWrapId={ "page-wrap" } /> <main id="page-wrap"> ・ ・ ・ </main> Outer container 全てのコンテンツをラップする親要素がある場合は, 親要素のidをouterContainerIdと以下のように一致させる。 <div id="outer-container"> <Menu pageWrapId={ "page-wrap" } outerContainerId={ "outer-container" } /> <main id="page-wrap"> ・ ・ ・ </main> </div> アニメーションの種類によってこれらのプロパティを指定しなければならない場合があるので, それらを以下の表で示しました。 slide, stack, bubble以外は基本的に指定する感じです。 Animation pageWrapId outerContainerId slide stack elastic ✔︎ ✔︎ bubble push ✔︎ ✔︎ pushRotate ✔︎ ✔︎ scaleDown ✔︎ ✔︎ scaleRotate ✔︎ ✔︎ fallDown ✔︎ ✔︎ reveal ✔︎ ✔︎ Position バーガーメニューアイコンの位置を指定できます。 デフォルトではアイコンは左に配置されるようになっていますが, 、右側に配置したい場合は以下のように指定できます。 <Menu right /> Width メニューの幅を以下のように指定できます。デフォルトは 300 です。 <Menu width={ 280 } /> <Menu width={ "280px" } /> <Menu width={ "20%" } /> Open state メニューの開閉の状態をisOpenで制御します。 デフォルトはfalseです。 Open menu handler ボタンなどを押してメニューを開く関数を渡すときに使用します。 <Menu onOpen={ handleOnOpen } /> Close menu handler ボタンやオーバーレイ(overlay)の部分などを押したときにメニューを閉じる関数を渡す時に使用します。 <Menu onClose={ handleOnClose } /> onOpenとonCloseはプロパティとして含めなくてもデフォルトで最低限の動作はしてくれます。 しかし, onOpenやonCloseを使うときは, 渡す関数内で必ず自身でメニューの開閉を処理するようにしなければなりません。 State change onStateChangeはコールバック関数を受け取り, メニューが開いているか閉じているかを検出することができます。onStateChangeに渡すコールバック関数の引数は, 最新の状態を保持するオブジェクトとなります。 let isMenuOpen = (state) => { return state.isOpen; }; <Menu onStateChange={ isMenuOpen } /> Close on Escape disableCloseOnEscプロパティを使用することで, Escキーを押した時にメニューが閉じる動作を無効にすることができます。これにより, レスポンシブメニューなどでメニューを常時開いておきたい場合などに便利です。 <Menu disableCloseOnEsc /> Custom keydown handler customOnKeyDownプロパティは, キーを押した際のメニューの状態を細かく制御することができます。例としては, 以下のようにMenuコンポーネントのインスタンスを複数使用している場合にEscキーを一度押すだけで全てのインスタンスを閉じる(メニューを全て閉じる)機能を実装する際に役立ちます。 const [areMenusOpen, setAreMenusOpen] = useState(false); const closeAllMenusOnEsc = (event) => { event = event || window.event; if (event.key === 'Escape' || event.keycode === 27) { setAreMenusOpen(false); } }; <MenuFirst customOnKeyDown={closeAllMenusOnEsc} isOpen={areMenusOpen} /> <MenuSecond customOnKeyDown={closeAllMenusOnEsc} isOpen={areMenusOpen} /> ※このプロパティを使用するとデフォルトのEscキーでメニューを閉じる機能が無効になるため, 例えばshiftキーを押したときにメニューを閉じる機能を実装した場合, Escキーは機能を失います。Escキーを使用したい場合は, 自身で関数内に処理を追加で記述する必要があります。 Overlay noOverlayプロパティを使用することで, デフォルトのオーバーレイ(overlay)をオフにすることができます。 <Menu noOverlay /> また, disableOverlayClickを使用することでオーバーレイ(overlay)を押した際のイベント(メニューが閉じるなど)を無効にすることができます。プロパティはブール値である必要があります。 <Menu disableOverlayClick /> <Menu disableOverlayClick={ () => shouldDisableOverlayClick() } /> Transitions noTransitionプロパティを使用することで, 全てのトランジションやアニメーションを無効にすることができます。 <Menu noTransition /> Custom icons customBurgerIcon, customCrossIconプロパティを使用することでデフォルトのバーガーアイコンとクロスアイコンを独自に置き換えることができます。 <Menu customBurgerIcon={ <img src="img/icon.svg" > } /> <Menu customCrossIcon={ <img src="img/cross-icon.svg" > } /> また, 各プロパティにfalseを渡すことでアイコン要素を無効にすることもできます。その場合は, ボタンなどを独自に作成してisOpenプロパティでメニューの開閉を制御します。 Custom ID and/or classNames MenuコンポーネントのプロパティとしてidとclassNameを指定することができます。 <Menu id={ "side-bar" } className={ "my-menu" } /> また, メニュー全体の各要素に対してプロパティとしてclassNameを指定することができます。(以下のclassNameは適当に考えたものです) <Menu burgerButtonClassName={ "burger-button" } burgerBarClassName={ "burger-bars" } crossButtonClassName={ "cross-button" } crossClassName={ "burger-cross" } menuClassName={ "burger-menu" } morphShapeClassName={ "burger-morph-shape" } itemListClassName={ "burger-item-list" } overlayClassName={ "burger-overlay" } /> また, html, body要素に対してclassNameを指定することもできます。 <Menu htmlClassName={ "html" } /> <Menu bodyClassName={ "body" } /> Focusing the first menu item デフォルトではメニューを開いた際にリストの最初の項目がフォーカスされた状態となっているため, disableAutoFocusプロパティを使用することで無効にすることができます。 <Menu disableAutoFocus /> Custom item list element メニューのリストは, nav要素にラップされており, ナビゲーションを使用しない場合はitemListElementプロパティでdivを指定します。 <Menu itemListElement /> Styling Menuコンポーネントは内部的にスタイルやアニメーションなどの処理を行います。 以下はバーガーメニューのスタイリングの例です。 CSS Menuコンポーネントは以下のクラスを持ちます。 /* バーガーボタンの位置とサイズ */ .bm-burger-button { position: fixed; width: 36px; height: 30px; left: 36px; top: 36px; } /* バーガボタンのバーのスタイル */ .bm-burger-bars { background: #373a47; } /* バーガーボタンのホバー */ .bm-burger-bars-hover { background: #a90000; } /* クロスボタンの位置とサイズ */ .bm-cross-button { height: 24px; width: 24px; } /* クロスボタンのカラー・形状 */ .bm-cross { background: #bdc3c7; } /* サイドバーのラッパースタイル - アニメーションが壊れる可能性があるため触るときは注意 */ .bm-menu-wrap { position: fixed; height: 100%; } /* サイドバーのスタイル */ .bm-menu { background: #373a47; padding: 2.5em 1.5em 0; font-size: 1.15em; } /* bubbleやelasticで必要なモーフの形状 */ .bm-morph-shape { fill: #373a47; } /* メニューリストのラッパースタイル*/ .bm-item-list { color: #b8b7ad; padding: 0.8em; } /* 個々のリストのスタイル */ .bm-item { display: inline-block; } /* オーバーレイ(overlay)のスタイリング */ .bm-overlay { background: rgba(0, 0, 0, 0.3); } CSS in JS Menuコンポーネントに以下のstylesオブジェクトを渡すことでスタイリングができます。 const styles = { bmBurgerButton: { position: 'fixed', width: '36px', height: '30px', left: '36px', top: '36px' }, bmBurgerBars: { background: '#373a47' }, bmBurgerBarsHover: { background: '#a90000' }, bmCrossButton: { height: '24px', width: '24px' }, bmCross: { background: '#bdc3c7' }, bmMenuWrap: { position: 'fixed', height: '100%' }, bmMenu: { background: '#373a47', padding: '2.5em 1.5em 0', fontSize: '1.15em' }, bmMorphShape: { fill: '#373a47' }, bmItemList: { color: '#b8b7ad', padding: '0.8em' }, bmItem: { display: 'inline-block' }, bmOverlay: { background: 'rgba(0, 0, 0, 0.3)' } } <Menu styles={ styles } /> 最後に なんかほぼ公式を和訳してちょっと脚色した感じなので, もし間違いなどあれば教えてい頂けますと幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

react-burger-menu is 何

はじめに react-burger-menu は簡単にバーガーメニューを作成できるReactのライブラリらしいです。 Next.jsの開発でバーガーメニュー作りたいなと思って調べたら出てきて使って見たらよかったので紹介します。 使い方 一応公式のREADME置いときます。 https://github.com/negomi/react-burger-menu 1. インストール(Installation) 以下のコマンドでインストールを行う npm install react-burger-menu --save or yarn add react-burger-menu TypeScriptを使っている方は以下のコマンドでインストール npm install @types/react-burger-menu --save or yarn add @types/react-burger-menu 2. 利用方法(Usage) アニメーション(animation)について react-burger-menuでは以下のようなアニメーションを選択できます。 ・slide ・stack ・elastic ・bubble ・push ・pushRotate ・scaleDown ・scaleRotate ・fallDown ・reveal 実際のアニメーションは公式が出しているサイトで見れます。 (https://negomi.github.io/react-burger-menu/) 使用する際は, ファイル内で以下のようにimportします。 import { slide as Menu } from 'react-burger-menu' この時, slide以外のアニメーションを使いたい場合は上で記述したアニメーションに適宜書き換えれば変更することができます。 プロパティ(Properties)について Page wrapper ページの残りをラップする要素は以下のようにMenuコンポーネントの後に配置し, idを一致させる。 <Menu pageWrapId={ "page-wrap" } /> <main id="page-wrap"> ・ ・ ・ </main> Outer container 全てのコンテンツをラップする親要素がある場合は, 親要素のidをouterContainerIdと以下のように一致させる。 <div id="outer-container"> <Menu pageWrapId={ "page-wrap" } outerContainerId={ "outer-container" } /> <main id="page-wrap"> ・ ・ ・ </main> </div> アニメーションの種類によってこれらのプロパティを指定しなければならない場合があるので, それらを以下の表で示しました。 slide, stack, bubble以外は基本的に指定する感じです。 Animation pageWrapId outerContainerId slide stack elastic ✔︎ ✔︎ bubble push ✔︎ ✔︎ pushRotate ✔︎ ✔︎ scaleDown ✔︎ ✔︎ scaleRotate ✔︎ ✔︎ fallDown ✔︎ ✔︎ reveal ✔︎ ✔︎ Position バーガーメニューアイコンの位置を指定できます。 デフォルトではアイコンは左に配置されるようになっていますが, 、右側に配置したい場合は以下のように指定できます。 <Menu right /> Width メニューの幅を以下のように指定できます。デフォルトは 300 です。 <Menu width={ 280 } /> <Menu width={ "280px" } /> <Menu width={ "20%" } /> Open state メニューの開閉の状態をisOpenで制御します。 デフォルトはfalseです。 Open menu handler ボタンなどを押してメニューを開く関数を渡すときに使用します。 <Menu onOpen={ handleOnOpen } /> Close menu handler ボタンやオーバーレイ(overlay)の部分などを押したときにメニューを閉じる関数を渡す時に使用します。 <Menu onClose={ handleOnClose } /> onOpenとonCloseはプロパティとして含めなくてもデフォルトで最低限の動作はしてくれます。 しかし, onOpenやonCloseを使うときは, 渡す関数内で必ず自身でメニューの開閉を処理するようにしなければなりません。 State change onStateChangeはコールバック関数を受け取り, メニューが開いているか閉じているかを検出することができます。onStateChangeに渡すコールバック関数の引数は, 最新の状態を保持するオブジェクトとなります。 let isMenuOpen = (state) => { return state.isOpen; }; <Menu onStateChange={ isMenuOpen } /> Close on Escape disableCloseOnEscプロパティを使用することで, Escキーを押した時にメニューが閉じる動作を無効にすることができます。これにより, レスポンシブメニューなどでメニューを常時開いておきたい場合などに便利です。 <Menu disableCloseOnEsc /> Custom keydown handler customOnKeyDownプロパティは, キーを押した際のメニューの状態を細かく制御することができます。例としては, 以下のようにMenuコンポーネントのインスタンスを複数使用している場合にEscキーを一度押すだけで全てのインスタンスを閉じる(メニューを全て閉じる)機能を実装する際に役立ちます。 const [areMenusOpen, setAreMenusOpen] = useState(false); const closeAllMenusOnEsc = (event) => { event = event || window.event; if (event.key === 'Escape' || event.keycode === 27) { setAreMenusOpen(false); } }; <MenuFirst customOnKeyDown={closeAllMenusOnEsc} isOpen={areMenusOpen} /> <MenuSecond customOnKeyDown={closeAllMenusOnEsc} isOpen={areMenusOpen} /> ※このプロパティを使用するとデフォルトのEscキーでメニューを閉じる機能が無効になるため, 例えばshiftキーを押したときにメニューを閉じる機能を実装した場合, Escキーは機能を失います。Escキーを使用したい場合は, 自身で関数内に処理を追加で記述する必要があります。 Overlay noOverlayプロパティを使用することで, デフォルトのオーバーレイ(overlay)をオフにすることができます。 <Menu noOverlay /> また, disableOverlayClickを使用することでオーバーレイ(overlay)を押した際のイベント(メニューが閉じるなど)を無効にすることができます。プロパティはブール値である必要があります。 <Menu disableOverlayClick /> <Menu disableOverlayClick={ () => shouldDisableOverlayClick() } /> Transitions noTransitionプロパティを使用することで, 全てのトランジションやアニメーションを無効にすることができます。 <Menu noTransition /> Custom icons customBurgerIcon, customCrossIconプロパティを使用することでデフォルトのバーガーアイコンとクロスアイコンを独自に置き換えることができます。 <Menu customBurgerIcon={ <img src="img/icon.svg" > } /> <Menu customCrossIcon={ <img src="img/cross-icon.svg" > } /> また, 各プロパティにfalseを渡すことでアイコン要素を無効にすることもできます。その場合は, ボタンなどを独自に作成してisOpenプロパティでメニューの開閉を制御します。 Custom ID and/or classNames MenuコンポーネントのプロパティとしてidとclassNameを指定することができます。 <Menu id={ "side-bar" } className={ "my-menu" } /> また, メニュー全体の各要素に対してプロパティとしてclassNameを指定することができます。(以下のclassNameは適当に考えたものです) <Menu burgerButtonClassName={ "burger-button" } burgerBarClassName={ "burger-bars" } crossButtonClassName={ "cross-button" } crossClassName={ "burger-cross" } menuClassName={ "burger-menu" } morphShapeClassName={ "burger-morph-shape" } itemListClassName={ "burger-item-list" } overlayClassName={ "burger-overlay" } /> また, html, body要素に対してclassNameを指定することもできます。 <Menu htmlClassName={ "html" } /> <Menu bodyClassName={ "body" } /> Focusing the first menu item デフォルトではメニューを開いた際にリストの最初の項目がフォーカスされた状態となっているため, disableAutoFocusプロパティを使用することで無効にすることができます。 <Menu disableAutoFocus /> Custom item list element メニューのリストは, nav要素にラップされており, ナビゲーションを使用しない場合はitemListElementプロパティでdivを指定します。 <Menu itemListElement /> Styling Menuコンポーネントは内部的にスタイルやアニメーションなどの処理を行います。 以下はバーガーメニューのスタイリングの例です。 CSS Menuコンポーネントは以下のクラスを持ちます。 /* バーガーボタンの位置とサイズ */ .bm-burger-button { position: fixed; width: 36px; height: 30px; left: 36px; top: 36px; } /* バーガボタンのバーのスタイル */ .bm-burger-bars { background: #373a47; } /* バーガーボタンのホバー */ .bm-burger-bars-hover { background: #a90000; } /* クロスボタンの位置とサイズ */ .bm-cross-button { height: 24px; width: 24px; } /* クロスボタンのカラー・形状 */ .bm-cross { background: #bdc3c7; } /* サイドバーのラッパースタイル - アニメーションが壊れる可能性があるため触るときは注意 */ .bm-menu-wrap { position: fixed; height: 100%; } /* サイドバーのスタイル */ .bm-menu { background: #373a47; padding: 2.5em 1.5em 0; font-size: 1.15em; } /* bubbleやelasticで必要なモーフの形状 */ .bm-morph-shape { fill: #373a47; } /* メニューリストのラッパースタイル*/ .bm-item-list { color: #b8b7ad; padding: 0.8em; } /* 個々のリストのスタイル */ .bm-item { display: inline-block; } /* オーバーレイ(overlay)のスタイリング */ .bm-overlay { background: rgba(0, 0, 0, 0.3); } CSS in JS Menuコンポーネントに以下のstylesオブジェクトを渡すことでスタイリングができます。 const styles = { bmBurgerButton: { position: 'fixed', width: '36px', height: '30px', left: '36px', top: '36px' }, bmBurgerBars: { background: '#373a47' }, bmBurgerBarsHover: { background: '#a90000' }, bmCrossButton: { height: '24px', width: '24px' }, bmCross: { background: '#bdc3c7' }, bmMenuWrap: { position: 'fixed', height: '100%' }, bmMenu: { background: '#373a47', padding: '2.5em 1.5em 0', fontSize: '1.15em' }, bmMorphShape: { fill: '#373a47' }, bmItemList: { color: '#b8b7ad', padding: '0.8em' }, bmItem: { display: 'inline-block' }, bmOverlay: { background: 'rgba(0, 0, 0, 0.3)' } } <Menu styles={ styles } /> 最後に なんかほぼ公式を和訳してちょっと脚色した感じなので, もし間違いなどあれば教えてい頂けますと幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

React Study(2) ~ React Hooks

React Hooks  昨日に引き続きReact学習中!昨日は勉強中に大きな地震があってなんかやめてしまった。。。  めげずに今日もやっていきましょう。 React Hooksとは  React Hooksは割と最近Reactに追加された機能。って言っても、自分は初学者なので最初からあるものとして勉強します。 フック (hook) は React 16.8 で追加された新機能です。state などの React の機能を、クラスを書かずに使えるようになります。 React公式 と、いうことで今まで面倒くさい実装してたのが楽になるよーっていう雑な解釈をします。 使いたい機能に対して「use~」を使うわけですね。 useState  state、つまり状態を管理するためのフックで、React使うなら基本中の基本とのこと。  画面に表示される値とかを扱うのに利用するのでほぼ必須機能と考えてよさそう。使うためにはコンポーネントの頭でuseStateをimportし、使いたい状態を入れる変数と状態を変更させる関数のセットをconstで宣言するだけ。 useState import React, {useState} from "react"; const [ stateValue, setState ] = useState("defalutValue");  こうやって宣言したstateValueを画面表示なんかに使ってあげると、そのあとsetStateで設定する値で更新してくれる。なるほど。これは便利。  よくあるサンプルのカウンタの実装とかだと、+1ボタン、-1ボタン、リセットボタンみたいなのを作って、それぞれのonClickから呼び出されるイベントの中でsetStateに+1,-1,0の値を渡してあげる感じ。  なお、今のstateValueの値、をsetStateの引数で受け取ることも出来るので、使いたい場合は値を受け取るアロー関数を記述する。 setState // 値を受け取らない setState(NEW_VALUE); // 値を受け取る(今の値+1を設定する) setState((current_value) => current_value + 1); useEffect  useEffectの公式説明は以下のような感じ。 副作用を有する可能性のある命令型のコードを受け付けます。 DOM の書き換え、データの購読、タイマー、ロギング、あるいはその他の副作用を、関数コンポーネントの本体(React のレンダーフェーズ)で書くことはできません。それを行うと UI にまつわるややこしいバグや非整合性を引き起こします。 代わりに useEffect を使ってください。useEffect に渡された関数はレンダーの結果が画面に反映された後に動作します。副作用とは React の純粋に関数的な世界から命令型の世界への避難ハッチであると考えてください。 デフォルトでは副作用関数はレンダーが終了した後に毎回動作しますが、特定の値が変化した時のみ動作させるようにすることもできます。  まぁ、ちょっと何言ってるのかわからない。日本語でおk。避難ハッチってなんだよ。  わからない場合はとりあえず動かしてみましょう。考えるんじゃなくて感じるんだ! useEffect(1) import React, { useEffect } from "react"; const TestComponent = () => { // コールバック関数を定義 const callbackFunction = () => console.log("コールバックが実行された!"); // useEffectでコールバック関数と、呼び出すタイミングをセット useEffect(callbackFunction,[]); return ( <h1>test</h1> ); } export default function App() { return <TestComponent />; }  コールバック関数を宣言して、それをuseEffect関数の第1引数へ。第2引数にはコールバックが呼ばれる契機になる変数なんかを入れた配列を渡します。今回は[]なので空配列。画面が初期レンダリングされたときに呼び出されます。 雑なサンプルですが実行結果はこんな感じ。  これだけのサンプルだとなんに使っていいかわからないですね。実際には、先のsetStateと組み合わせて特定のstateが変化したときにその値を表示したり、とかに利用します。 useEffect(2) const [ stateValue, setState ] = useState(INIT); const callbackFunction = () => { document.title = `${count}`; } useEffect(callbackFunction,[count]);  こうしてやると、countの値が変わるたびにブラウザタブに表示されるタイトルが変わる(意味は、ない。)。 クリーンアップ関数  より実用的に使おうとすると、コールバック関数の中でリソースをつかんだり、タイマーをセットしたり、などを行うことになる。  そうするとちょっとした問題があって、例えばタイマーでポップアップウィンドウを開いたりする仕組みにすると、次にまたコンポーネントが再描画されるときに次のタイマーが新しく作られてしまい、どんどんイベントが重複していく問題にぶちあたる。これを解消するための仕組みがクリーンアップ関数。コールバック関数の中で定義してやることになる。 useEffect(3) const callbackFunction = () => { // 例えばタイマーセット const timer = setInterval(alert("!!!",1000)); // クリーンアップ関数 return () => { clearInterval(timer); } }  なんとなくわかったようなわからないような。  useEffectに関してはすでに有益な記事がたくさんあるのでそちら参照したほうが良い(元も子もない) React Hooks の useEffect の正しい使い方  まず、初学者が初見ですらすら使える類の機能じゃないが、React使う上では必須になってくるところなので今後経験積みながら覚えていくしかなさそう。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Material UI v5 と Emotion の環境構築

以前 Material UI と Emotion を使った環境構築について記事を書いたのですが、Material UI が v4 から v5 にアップデートされたので、今回は以前の記事のリライトになります。 前提 【React】Material-UI v4 と Emotion を併用するときの環境構築の記事のリライトになります。 記事執筆時点で Material UI のバージョンは v5 なります。 npm ではなく yarn を使っています。 React の環境構築 まずは create-react-app の typescript テンプレートを利用してプロジェクトを作成します。今回はプロジェクト名を myapp にします。 $ npx create-react-app myapp --template typescript Material UI v5 と Emotion のインストール スタイリングシステムが変更され emotion or styled-components が必須になりました。今回はタイトルにある通り emotion をインストールします。 $ yarn add @mui/material @emotion/react @emotion/styled もし styled-components を使いたい場合は以下のコマンドでインストールできます。 $ yarn add @mui/material @mui/styled-engine-sc styled-components 一旦動くか確認してみましょう。不要なコードを消して App.tsx を以下に変更します。 myapp/src/App.tsx import React from "react"; import Stack from "@mui/material/Stack"; import Button from "@mui/material/Button"; const App: React.FC = () => { return ( <Stack spacing={2} direction="row"> <Button variant="text">Text</Button> <Button variant="contained">Contained</Button> <Button variant="outlined">Outlined</Button> </Stack> ); }; export default App; スタイリングの方法 v5 から makeStyle ではなく styled が推奨になったようです。以下の書き方でスタイルが反映されます。 myapp/src/App.tsx import React from "react"; import { styled } from "@mui/material/styles"; import Button from "@mui/material/Button"; const MyButton = styled(Button)({ backgroundColor: "red", "&:hover": { backgroundColor: "red", }, }); const App: React.FC = () => { return <MyButton variant="contained">ボタン</MyButton>; }; export default App; また sx props というの新しいスタリングの方法が導入されました。ユーティリティファーストな書き方ができます。 myapp/src/App.tsx import React from "react"; import { styled } from "@mui/material/styles"; import Button from "@mui/material/Button"; const App: React.FC = () => { return ( <Button variant="contained" sx={{ backgroundColor: "red", "&:hover": { backgroundColor: "red", }, }} > ボタン </Button> ); }; export default App; Emotion の css prop を使う 公式で推奨されているわけではないですが css prop を使いたい方は以下のように書くことができます(個人的に css prop を使っているので、以降のスタイリングも css prop を使っていきます)。 myapp/src/App.tsx /** @jsxImportSource @emotion/react */ import React from "react"; import { css } from "@emotion/react"; import Button from "@mui/material/Button"; const style = css` background-color: red; &:hover { background-color: red; } `; const App: React.FC = () => { return ( <Button variant="contained" css={style}> ボタン </Button> ); }; export default App; CRACO のインストール /** @jsxImportSource @emotion/react */ を毎回書くのは面倒なので CRACO をインストールします。CRACO は create-react-app の設定を上書きするときに使えるライブラリになります。 $ yarn add @craco/craco craco.config.js をルートに作り babel の設定を上書きします。 myapp/craco.config.js module.exports = { babel: { presets: [ [ "@babel/preset-react", { runtime: "automatic", importSource: "@emotion/react" }, ], ], plugins: ["@emotion/babel-plugin"], }, }; App.tsx ファイルから /** @jsxImportSource @emotion/react */ の記述を消してもスタイルが反映されるようになりました。 myapp/src/App.tsx import React from "react"; import { css } from "@emotion/react"; import Button from "@mui/material/Button"; const style = css` background-color: red; &:hover { background-color: red; } `; const App: React.FC = () => { return ( <Button variant="contained" css={style}> ボタン </Button> ); }; export default App; Theme を Material UI と Emotion で共有する Emotion の css prop で Material UI の Theme を使えるようにします。 まずは index.tsx を以下のように書き換えます。 myapp/index.tsx import React from "react"; import ReactDOM from "react-dom"; import App from "./App"; import reportWebVitals from "./reportWebVitals"; import { ThemeProvider } from "@emotion/react"; import { createTheme, ThemeProvider as MUThemeProvider, } from "@mui/material/styles"; const theme = createTheme(); ReactDOM.render( <React.StrictMode> <MUThemeProvider theme={theme}> <ThemeProvider theme={theme}> <App /> </ThemeProvider> </MUThemeProvider> </React.StrictMode>, document.getElementById("root") ); reportWebVitals(); emotion.d.ts ファイルを作成し Emotion の Theme 型に Material UI の Theme 型を継承します。 myapp/src/types/emotion.d.ts import { Theme as MUTheme } from "@mui/material/styles"; declare module "@emotion/react" { export interface Theme extends MUTheme {} } App.tsx を以下のように書き換えます。Emotion からも Material UI の Theme が使えるようになっていますね。 myapp/src/App.tsx import React from "react"; import { css, Theme } from "@emotion/react"; import Button from "@mui/material/Button"; const style = (theme: Theme) => css` color: ${theme.palette.error.light}; `; const App: React.FC = () => { return ( <Button variant="contained" css={style}> ボタン </Button> ); }; export default App; Theme の拡張 次にテーマを拡張したいときの設定方法になります。 テーマの拡張には主に 3 パターンあると思っています。 Theme の上書きをしたいとき Theme に新規項目を加えたいとき すでにある Theme を拡張したいとき 順番に書いていきます。 Theme の上書きをしたいとき 上書きしたいだけならシンプルです。 createTheme で該当する値を上書きすれば問題ありません。 const theme = createTheme({ typography: { fontFamily: `"Meiryo", "メイリオ", sans-serif`, }, }); Theme に新規項目を加えたいとき 次に新しい項目を作成したいときです。 「Theme の上書きをしたいとき」と同様に createTheme に新しく加えたい値を書きます。 この時点では型定義のエラーが出るかもしれませんが、次の作業で対応します。 const theme = createTheme({ headerHeight: 100, }); 型の拡張をおこなます。 material-ui.d.tsという名前(任意の名前で OK)でファイルを作り、以下のように書きます。 Theme と ThemeOptions の両方で型を拡張します。 material-ui.d.ts import { Theme, ThemeOptions } from "'@mui/material/styles"; declare module "@mui/material/styles" { interface Theme { headerHeight: number; } interface ThemeOptions { headerHeight: number; } } すでにある Theme を拡張したいとき 基本的には、「Theme に新規項目を加えたいとき」と同じです。 以下は typography に font-size を計算する新しい関数を追加しています。 const theme = createTheme({ typography: { size: (n: number) => n * 4, }, }); material-ui.d.ts import { Typography, TypographyOptions, } from "@mui/material/styles/createTypography"; declare module "@mui/material/styles/createTypography" { interface Typography { size: (number) => number; } interface TypographyOptions { size: (number) => number; } } 型定義は myapp/node_modules/@mui/material/styles/createTheme.d.ts で確認できます。 以下のように型定義されているので、必要そうなところを拡張するといった感じです。 createTheme.d.ts /** 略 **/ export interface ThemeOptions extends SystemThemeOptions { mixins?: MixinsOptions; components?: Components; palette?: PaletteOptions; shadows?: Shadows; transitions?: TransitionsOptions; typography?: TypographyOptions | ((palette: Palette) => TypographyOptions); zIndex?: ZIndexOptions; unstable_strictMode?: boolean; } export interface Theme extends SystemTheme { mixins: Mixins; components?: Components; palette: Palette; shadows: Shadows; transitions: Transitions; typography: Typography; zIndex: ZIndex; unstable_strictMode?: boolean; } /** 略 **/ 一旦ここまでの対応を踏まえて、以下のように書き換えます。Theme の拡張を行えていることが確認できると思います。 myapp/index.tsx import React from "react"; import ReactDOM from "react-dom"; import App from "./App"; import reportWebVitals from "./reportWebVitals"; import { ThemeProvider } from "@emotion/react"; import { createTheme, ThemeProvider as MUThemeProvider, } from "@mui/material/styles"; const theme = createTheme({ headerHeight: 100, typography: { fontFamily: `"Meiryo", "メイリオ", sans-serif`, size: (n: number) => n * 4, }, }); ReactDOM.render( <React.StrictMode> <MUThemeProvider theme={theme}> <ThemeProvider theme={theme}> <App /> </ThemeProvider> </MUThemeProvider> </React.StrictMode>, document.getElementById("root") ); reportWebVitals(); myapp/src/App.tsx import React from "react"; import { css, Theme } from "@emotion/react"; import Button from "@mui/material/Button"; const headerStyle = (theme: Theme) => css` height: ${theme.headerHeight}px; background: ${theme.palette.primary.main}; `; const textStyle = (theme: Theme) => css` color: ${theme.palette.text.primary}; `; const buttonStyle = (theme: Theme) => css` font-size: ${theme.typography.size(10)}px; `; const App: React.FC = () => { return ( <div> <header css={headerStyle}>ヘッダー</header> <p css={textStyle}>サンプルテキスト</p> <Button variant="contained" css={buttonStyle}> ボタン </Button> </div> ); }; export default App; material-ui.d.ts import { Theme, ThemeOptions } from "'@mui/material/styles"; declare module "@mui/material/styles" { interface Theme { headerHeight: number; } interface ThemeOptions { headerHeight: number; } } import { Typography, TypographyOptions, } from "@mui/material/styles/createTypography"; declare module "@mui/material/styles/createTypography" { interface Typography { size: (number) => number; } interface TypographyOptions { size: (number) => number; } } Global CSS の設定 Global CSS は Emotion の Global Styles 機能を使います。 Global を Emotion から import して、Global CSS を定義します。 myapp/src/styles/GlobalStyles.tsx import React from "react"; import { Global, css, Theme } from "@emotion/react"; const global = (theme: Theme) => css` html, body { width: 100%; height: 100%; margin: 0; font-family: ${theme.typography.fontFamily}; } `; const GlobalStyles: React.FC = () => { return <Global styles={global} />; }; export default GlobalStyles; 上記で作成したファイルを index.tsx で読み込むだけで Global な CSS を設定できます。 myapp/src/index.tsx import React from "react"; import ReactDOM from "react-dom"; import App from "./App"; import reportWebVitals from "./reportWebVitals"; import { ThemeProvider } from "@emotion/react"; import { createTheme, ThemeProvider as MUThemeProvider, } from "@mui/material/styles"; import GlobalStyles from "./styles/GlobalStyles"; const theme = createTheme({ headerHeight: 100, typography: { fontFamily: `"Meiryo", "メイリオ", sans-serif`, size: (n: number) => n * 4, }, }); ReactDOM.render( <React.StrictMode> <MUThemeProvider theme={theme}> <ThemeProvider theme={theme}> <GlobalStyles /> <App /> </ThemeProvider> </MUThemeProvider> </React.StrictMode>, document.getElementById("root") ); reportWebVitals(); まとめ Material UI v5 における環境構築の話でした。 v4 から変更された部分も結構ありますので、参考にしていただけると幸いです。 参考 URL https://mui.com/ https://emotion.sh/docs/introduction https://github.com/gsoft-inc/craco https://zenn.dev/h_yoshikawa0724/articles/2021-09-26-material-ui-v5
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む