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

Gatsby.jsで「ModuleBuildError: Module build failed : SyntaxError: Only one default export allowed per module.」というエラーが出たときの対処法

エラーメッセージ ModuleBuildError: Module build failed (from ./node_modules/gatsby/dist/utils/babel-loader.js): SyntaxError: /Users/user_name/git/maiamea/portfolio/src/pages/hello.jsx: Only one default export allowed per module. (31: 0) 29 | 30 | export default HelloPage > 31 | export default Example | ^ エラー発生時のコード src/pages/hello.jsx import React, { useState } from 'react'; const HelloPage = () => { return ( <main> <h1>Hello, World!!!</h1> <p style={ {color:"red"} }>こんにちは</p> <h2>はじめてのGatsby</h2> </main> ) } function Example() { const [count, setCount] = useState(0); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count+1)}> Click me </button> </div> ) } export default HelloPage export default Example 原因 1つのファイル内にexport defaltを複数書いていた。 対処法 export defaultには起点となるコンポーネントを書き、一緒のページに表示させたい他のコンポーネントは、起点となるコンポーネント内に<ExampleComponent></ExampleComponent>のように埋め込む。 修正後 src/pages/hello.jsx import React, { useState } from 'react'; const HelloPage = () => { return ( <main> <h1>Hello, World!!!</h1> <p style={ {color:"red"} }>こんにちは</p> <h2>はじめてのGatsby</h2> <ExampleComponent></ExampleComponent> </main> ) } function ExampleComponent() { const [count, setCount] = useState(0); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count+1)}> Click me </button> </div> ) } export default HelloPage 実行結果(ブラウザ) 参考サイト export defaultってなんだろう MDN Export コンポーネントとprops
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Next.jsでIEブロックを行う

動作対象外のブラウザ(IE)でアクセスされた際、警告を出したい場合がありました。 Vue.jsの場合は、index.htmlに直に判定文を記述すればよかったのですが、Next.jsでのやり方がわからず苦戦しました。 調べてみると、当然ながらサポートしていないブラウザで動作させるのでNext.jsのアプリケーション内で制御するのはあまり良くなさそうなので、実現方法を考えてみました。 これ以外にも他にもっといい方法があるかもしれませんが、とりあえず残しておきます。 ※コードはTypeScriptです。 IE判定 こんな感じでメッセージを出したいが、pages/_app.tsxに記述するとエラーになる。 if (window.document.documentMode) { document.write('IEはサポートしていません') } _document.tsxの追加 そこで、_document.tsxを利用する。 _document.jsの詳細はこちら _document.tsx import NextDocument, { Html, Head, Main, NextScript } from 'next/document' export default class MyDocument extends NextDocument { render() { return ( <Html> <Head> <script async src="./scripts/checkBrowser.js" /> </Head> <body> <Main /> <NextScript /> </body> </Html> ) } } ブラウザの判定ロジックはpublic/scripts/checkBrowser.jsに記述する checkBrowser.js if (window.document.documentMode) { window.location.replace('../ie.html') } IEの場合、メッセージを表示する用のHTML(public/ie.html)を読み込む ie.html <html> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <title>Unsupported browser</title> </head> <body> <p> InternetExplorer(IE)はサポートされていません。最新のブラウザ(Edge)をご利用ください。 </p> </body> </html> まとめ _document.tsxを利用することで、どのURLにアクセスされてもブラウザ判定が可能
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

React×TypeScriptで天気アプリ作成記録

1.はじめに 初めまして。未経験からプログラミングを始めて4ヶ月目に突入したので、アウトプットも兼ねてはじめて記事を投稿してみました。 お世話になった記事がたくさんあるので、備忘録として残しておきます。 2.天気APIを使用したアプリケーション作成 【アプリの概要】1日の天気が確認でき、気象情報に応じて服装を教えてくれる 【作成した経緯】 TypeScriptを学習し始めて、慣れるためにも3大フレームワークの中で1番相性がいいとされているReactと併用したアプリケーション制作を行おうと考えました。 またデザインも個人的に使い勝手がいいなと感じたTailwindCSSを用いました。 【使用した技術・API】 ・React ・TypeScript ・OpenWeatherMapAPI →Call 5 day / 3 hour forecast dataを使用 https://openweathermap.org/forecast5 ・TailwindCSS 【実装した機能】 ・検索欄に入力した地名、もしくはドロップダウンメニューから選択した地名の気象情報を検索 ・検索した地域のその日の天気、気温が3時間ごとに表示される ・気温をもとにおすすめの服装を表示 3.実現したかったこと ・現在地を取得して、現在地をもとに気象情報を表示する機能 ・5日間の予報(最高気温、最低気温は算出できたものの曇り晴れなどの気象情報の表示を実現できなかった) 改善点 ・時間の表示 ・検索した地名にヒットしなかった時の処理 技術力と時間の都合で実現できなかった点が多いので、今後も機能の追加など ブラッシュアップしていきたいと思います。 4.参考サイト
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

React + TypeScript: setInterval()をReactのプログラミングモデルに合わせてフックに書き替える ー useInterval

setInterval()をフックに書き替えたuseIntervalの作例 Reactのとくに関数コンポートでsetInterval()を使うと、やっかいに巻き込まれることが少なくありません。Reactのプログラミングモデルと相性がよくないからです。そこで、面倒なことを考えずに済むように、フック(useInterval)に書き替えてみましょう(サンプル001)。 サンプル001■useIntervalフックを使ったカウンターの作例 >> CodeSandboxへ 本稿の作例は、Create React AppでReactアプリケーションのひな型をつくりました。TypeScriptも組み込むため、コマンドラインツールでnpx create-react-app プロジェクト名に、オプション--template typescriptを添えます(「Create React AppでTypeScriptが加わったひな形アプリケーションをつくる」参照)。 setInterval()のどこが煩わしいのか setInterval()でやっかいに巻き込まれるコード例をつぎに示します。1秒ごとにカウントアップするカウンターです。副作用ですので、useEffectフックに定め、クリーンアップの処理(clearInterval())はコールバック関数にして返します。今回の作例では、ひたすらカウントアップをし続けるだけです。つまり、setInterval()ははじめに1度呼び出せばよいので、useEffectフックの第2引数、依存配列は空([])にしました。 src/App.tsx import React, { useEffect, useState } from 'react'; function App() { const [count, setCount] = useState(0); const [delay, setDelay] = useState(1000); useEffect(() => { const interval = setInterval(() => { console.log(count); // 出力: 0 setCount(count + 1); }, delay); return () => clearInterval(interval); }, []); return ( <> <h1>{count}</h1> </> ); } export default App; 実行すると、カウンターの数値は0から1になったまま変わりません。インターバルの加算が止まったのかとブラウザのコンソールを見ると、変数(count)の値として0が何度も出力されています(console.log())。つまり、処理そのものは繰り返されており、ただもとの数値が0なので、加算した1が設定されているということです。 なぜ、インターバルのカウンター(count)数値は更新されないのでしょう。それは、はじめに副作用(useEffect)が実行されたとき、setInterval()のコールバック関数は状態変数(count)の値をクロージャに保持してしまい、インターバルのたびに新たな状態変数値を参照し直さないからです。 これを避けるには、useEffectの第2引数の依存配列に状態変数(count)を加えることが考えられます。状態変数が変わるたびに、クリーンアップの処理が行われ、新たな変数値にもとづいてsetInterval()が呼び出されるということです1。 src/App.tsx function App() { useEffect(() => { const interval = setInterval(() => { setCount(count + 1); }, delay); // }, []); }, [count]); } もうひとつ、状態変数の設定関数(setCount)呼び出しを関数型の更新にする手もあります。引数の関数に渡されるのは、最新の状態変数値です。その値に加算して返せばカウンターは正しくカウントアップされます。 src/App.tsx function App() { useEffect(() => { const interval = setInterval(() => { // setCount(count + 1); setCount((count) => ++count); }, delay); }, []); } けれど、本稿のお題は、このようなやっかいごとに巻き込まれずに済むインターバルのカスタムフック(useInterval)を定めることです。順を追って考えてゆきましょう。 setInterval()の処理をフックuseIntervalに書き替える インターバルのカスタムフックuseIntervalは、つぎのように副作用(useEffect)をフック内部に取り込みます。引数はsetInterval()と同じ、コールバック関数(callback)とインターバルミリ秒(delay)です。後者はsetInterval()に渡すとき、デフォルト値を0にしました。 src/useInterval.ts import { useEffect } from 'react'; const useInterval = (callback: Function, delay?: number) => { useEffect(() => { const interval = setInterval(() => callback() , delay || 0); return () => clearInterval(interval); }, [callback, delay]); } export default useInterval; フックuseIntervalは、ルートモジュールsrc/App.tsxから、コンポーネント(App)内でつぎのように単純に呼び出すだけです。副作用はフックが扱いますから、煩わされることはありません。 src/App.tsx // import React, { useEffect, useState } from 'react'; import React, { useState } from 'react'; import useInterval from './useInterval'; function App() { /* useEffect(() => { const interval = setInterval(() => { console.log('render:', count); setCount(count + 1); }, delay); return () => clearInterval(interval); }, []); */ useInterval(() => { console.log('render:', count); // 確認用 setCount(count + 1); }, delay); } useIntervalフックの引数でインターバルの間隔を変える フックuseIntervalでは、インターバルの間隔(delay)を副作用(useEffect)の依存配列に加えました。それは、フックを使う側から、間隔が自由に変えられるということです。そこで、ルートモジュールsrc/App.tsxのコンポーネント(App)には、つぎのように数値の入力フィールド(<input type="number">)を加えて、インターバルのミリ秒が設定できるようにしました。 src/App.tsx function App() { const handleDelayChange: React.ChangeEventHandler<HTMLInputElement> = (event) => { setDelay(Number(event.target.value)); } return ( <> <input type="number" value={delay} onChange={handleDelayChange} /> </> ); } 書き替えるのはこのルートモジュール(src/App.tsx)の修正だけです。フックuseIntervalに手は加えません。これだけで、入力フィールドの数値で、インターバルの間隔が変わるようになりました。 インターバル処理を一時停止する つぎは、フックuseIntervalに新たな機能を加えましょう。インターバルの処理を一時停止することです。フックの第2引数(delay)をnullに設定したとき、一時停止とします。といっても書き替えは、つぎのようにフックの第2引数の型づけを改め、条件判定をひとつ加えるだけです。 src/useInterval.ts // const useInterval = (callback: Function, delay?: number) => { const useInterval = (callback: Function, delay?: number | null) => { useEffect(() => { if (delay !== null) { const interval = setInterval(() => callback() , delay || 0); } }, [callback, delay]); } ルートモジュール(src/App.tsx)のコンポーネント(App)には、チェックボックス(<input type="checkbox">)を加えて、値は状態変数(isRunning)に定めました。フックuseIntervalの第2引数をこの変数で切り替えれば、インターバルの処理が一時停止できるのです。 src/App.tsx function App() { const [isRunning, setIsRunning] = useState(true); useInterval(() => { // }, delay); }, isRunning ? delay : null); const handleIsRunningChange: React.ChangeEventHandler<HTMLInputElement> = (event) => { setIsRunning(event.target.checked); } return ( <> <h1>{count}</h1> <input type="checkbox" checked={isRunning} onChange={handleIsRunningChange} /> Running <br /> </> ); } これで一旦、フックuseIntervalの動きはできました。ルートモジュールsrc/App.tsxと合わせて、つぎのコード001にそれぞれの記述全体をまとめましょう。 コード001■ useIntervalフックを使ったカウンターサンプル src/App.tsx import React, { useState } from 'react'; import useInterval from './useInterval'; function App() { const [count, setCount] = useState(0); const [delay, setDelay] = useState(1000); const [isRunning, setIsRunning] = useState(true); useInterval(() => { console.log('render:', count); setCount(count + 1); }, isRunning ? delay : null); const handleDelayChange: React.ChangeEventHandler<HTMLInputElement> = (event) => { setDelay(Number(event.target.value)); } const handleIsRunningChange: React.ChangeEventHandler<HTMLInputElement> = (event) => { setIsRunning(event.target.checked); } return ( <> <h1>{count}</h1> <input type="checkbox" checked={isRunning} onChange={handleIsRunningChange} /> Running <br /> <input type="number" value={delay} onChange={handleDelayChange} /> </> ); } export default App; src/useInterval.ts import { useEffect } from 'react'; const useInterval = (callback: Function, delay?: number | null) => { useEffect(() => { if (delay !== null) { const interval = setInterval(() => callback() , delay || 0); return () => clearInterval(interval); } }, [callback, delay]); } export default useInterval; コールバック関数をRefに設定する フックuseIntervalの副作用の依存配列を、改めて見直します。インターバル間隔(delay)はよいとして、コールバック(callback)が変わったからといってsetInterval()を呼び直さなくてもよいはずです。関数の参照さえ改めれば済みます。 そういうときに用いるのがRefオブジェクトです(「インスタンス変数のようなものはありますか?」参照)。Refオブジェクトのcurrentプロパティは、レンダーによって改められることがなく、値が変わっても再描画は引き起こしません(「useRef」参照)。 そこで、副作用(useEffect)をコールバック(callback)とインターバル間隔(delay)でつぎのように分けます。コールバックはRefオブジェクト(savedCallback)のcurrentプロパティ値の参照を改めるだけです。レンダーはし直しません。インターバル間隔が変わったときに、setInterval()を呼び出し直して再描画します。 src/useInterval.ts // import { useEffect } from 'react'; import { useEffect, useRef } from 'react'; const useInterval = (callback: Function, delay?: number | null) => { const savedCallback = useRef<Function>(() => {}); useEffect(() => { savedCallback.current = callback; }, [callback]); useEffect(() => { if (delay !== null) { const interval = setInterval(() => // callback() savedCallback.current() , delay || 0); } // }, [callback, delay]); }, [delay]); } 書き改めたフックuseIntervalの記述を、つぎのコード002に掲げます。実は、このコードは、react-useのuseIntervalをもとにしました。フックがつくられたきっかけは、Dan Abramov氏のblog記事「Making setInterval Declarative with React Hooks」です。実装は、細かいところが少し異なります。さらに、本稿ではコールバック(savedCallback)に対する副作用の依存(callback)を加えました(「Should only run effect when callback changes」参照)。実際のコードの動きは、冒頭に掲げたサンプル001のCodeSandbox作例をご参照ください。 コード002■コールバック関数をRefに設定したuseIntervalフック src/useInterval.ts import { useEffect, useRef } from 'react'; const useInterval = (callback: Function, delay?: number | null) => { const savedCallback = useRef<Function>(() => {}); useEffect(() => { savedCallback.current = callback; }, [callback]); useEffect(() => { if (delay !== null) { const interval = setInterval(() => savedCallback.current() , delay || 0); return () => clearInterval(interval); } return undefined; }, [delay]); } export default useInterval; このコード例では、インターバルのたびに変数値がカウントアップされ、クリーンアップのあとsetInterval()が呼び直されます。ですから、setTimeout()(クリーンアップはclearTimeout())に書き替えても動きは同じです。 ↩
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

React×TypeScriptで作ったポートフォリオサイトの説明

作成したサイト 実現したいこと ・自分の経歴、能力、作品などが伝わるポートフォリオサイトの作成 ・SPAによる高速なページ遷移 ・必要な人のみ閲覧してもらえばいいのでSEO対策は考えない ・学習コストが増えすぎるのを防ぐため、サーバーサイドは考慮しなくていい構成にする ・同様の理由で必要以上のフレームワーク、ライブラリを導入しすぎないようにする ・レスポンシブ対応の実装 ・チーム開発を意識したコーディングを心掛ける 使用技術 フロントエンド React, React-Router, React-Hook-Form, EmailJS, TypeScript, styled-component, styled-media-query, Material-UI, react-vertical-timeline-component Yarn, Prettier ツール Git, GitHub, git-Flow, GitHub-Pages 個人的に今一番人気があると感じているJavaScriptライブラリであるReactと、今後は新規開発で使われることになりそうなTypeScriptを採用しました。cssライブラリとしてコンポーネント指向と相性の良いstyled-componentsを採用しました。あまりデザインに時間をかけすぎたくなかったのでMaterial-UIも採用しています。ホスティングはGitHub-Pagesで行っています。 ディレクトリ構成 ディレクトリ構成はcreate-react-appコマンドで作成したプロジェクトディレクトリにatomic designを適用して決めました。organismsやmoluculesは将来的に分割が予想されるコンポーネントも配置しています。コンポーネントを分割する際は再利用性がある場合と可読性の向上のための2つの場合に分けて行いました。 reactPortfolio ├── build ├── node_modules ├── package.json ├── public │ └── index.html ├── README.md ├── src │ ├── App.tsx │ ├── assets │ │ ├── data //配列などのデータ格納ディレクトリ │ │ ├── images //画像格納ディレクトリ │ │ ├── styles │ │ │ ├── media.tsx //styled-media-queryのラッパーファイル │ │ │ └── theme.tsx //Material-UI用のカラーテーマファイル │ │ └── Type.tsx │ ├── components │ │ ├── atoms │ │ ├── molecules │ │ ├── organisms │ │ ├── pages │ │ └── templates │ ├── index.tsx │ ├── react-app-env.d.ts │ └── ComponentRouter.tsx //ルーターファイル ├── tsconfig.json ├── types │ └── import-jpg.d.ts └── yarn.lock コーディング規則 型定義 ・関数コンポーネントにはアロー関数を使い、型定義は「VFC」で行う。 ・childrenを使いたい場合は"PropsType"に型定義して使うこと。 ・基本的に関数コンポーネントの返り値に型注釈はつけない。 ・anyは使用禁止。 スタイル ・一行で済むスタイリングも基本的にはstyled-coponentsでスタイルコンポーネントを作成する。 ・スタイルが2行以上に拡張される確率が非常に低いと判断される場合はインラインスタイルを使用してもよい。 ・スタイルコンポーネントは関数コンポーネントの後に記述し、登場するスタイルコンポーネントの順に書く ・レスポンシブ対応はstyled-media-queryを用いて行い、レスポンシブ対応しているcssプロパティは下の部分に寄せて改行する。 命名規則 ・スタイルコンポーネントの名前は"S + キャメルケースの名称"とする。 ・複数要素を囲うタグの名前は”意味を推測しやすい名前 + Container”とする。"Wrapper"は混乱を避けるため利用しない。 ・コンポーネント全体を囲うタグの名前は”SComponentContainer”とする。 ・命名は"Container"などを含めて4単語までのキャメルケースで行い、5単語以上になる場合は1単語を省略するか異なる命名を考える。 ・型定義の末尾には"Type"とつける。 ・propsの型名は"PropsType"とする。 その他 ・短絡評価によるコンポーネントの表示、非表示は行わず、三項演算子で実現する。 ・importのエリアはライブラリ、material-uiなどのスタイル、自作関数コンポーネントや型定義や配列データ、に分けて改行を入れる。 ・importの3つ目のエリア内では一番上が型定義、その次が配列や画像などのデータ、最後に自作関数コンポーネントの順に記述する。 ・コンポーネント内のreturn文の前の定数宣言同士に改行をいれない。 ・将来的に数が大きくなる可能性がある定数配列などはdataフォルダに格納し、インポートして使う。 工夫した点 atomic designによるディレクトリ構成 atomic designを利用することでコンポーネントがどのように利用されるのかが分かりやすくなり、可読性も向上しました。 コーディング規則による統一性 自分以外の人間がコーディングをしたとしても同じようなコーディングになるように自分なりに規則を決めてコーディングしました。 styled-media-queryを用いたレスポンシブ対応 そのまま記述することも考えましたが、ブレイクポイントを数値で書くのは非常に危険だと考え、別ファイルに書いてインポートするなども考えましたが少し手間でした。何か良いライブラリがないかと探した際にstyled-media-queryを見つけましたが、そもそもの記述が少し冗長だったのでラップして短く、安全にレスポンシブ対応を行うことが出来ました。今回のポートフォリオではブレイクポイントを1170pxと768pxの2つに設定してレスポンシブ対応を行っています。 //そのままのstyled-media-query const SText = styled.h1` font-size: 64px; ${media.between("medium","large")` font-size: 36px; `} ${media.lessThan("medium")` font-size: 26px; `} `; //ラップして簡略化したもの const SText = styled.h1` font-size: 64px; ${media.lg` font-size: 36px; `} ${media.md` font-size: 26px; `} `; 簡潔で分かりやすいデザイン Material-UIやreact-vertical-timeline-componentを利用した簡潔で分かりやすいデザインを心掛けました。 反省点 レスポンシブ対応がモバイルファーストでない モバイルファーストで設計した方が良いことは知っていたのですが、具体的にどうすれば良いのかわからずPCをベースにスタイリングしていった結果、あとから大幅な修正をすることになりました。 おわりに モダンな技術を用いてポートフォリオサイトを作成しました。作ってみないと分からないことがたくさんあったので良い経験になりました。次はサーバーサイドの技術を含めた作品を作りたいと思います。 参考文献
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

React×TypeScriptで作ったポートフォリオサイトを作成した

はじめに React、TypeScriptを使った初めての作品として自己紹介サイトを作成しました。 作成したサイト 実現したいこと ・自分の経歴、能力、作品などが伝わるポートフォリオサイトの作成 ・SPAによる高速なページ遷移 ・必要な人のみ閲覧してもらえばいいのでSEO対策は考えない ・学習コストが増えすぎるのを防ぐため、サーバーサイドは考慮しなくていい構成にする ・同様の理由で必要以上のフレームワーク、ライブラリを導入しすぎないようにする ・レスポンシブ対応の実装 ・チーム開発を意識したコーディングを心掛ける 使用技術 フロントエンド React, React-Router, React-Hook-Form, EmailJS, TypeScript, styled-component, styled-media-query, Material-UI, react-vertical-timeline-component Yarn, Prettier ツール Git, GitHub, git-Flow, GitHub-Pages 個人的に今一番人気があると感じているJavaScriptライブラリであるReactと、今後は新規開発で使われることになりそうなTypeScriptを採用しました。cssライブラリとしてコンポーネント指向と相性の良いstyled-componentsを採用しました。あまりデザインに時間をかけすぎたくなかったのでMaterial-UIも採用しています。ホスティングはGitHub-Pagesで行っています。 ディレクトリ構成 ディレクトリ構成はcreate-react-appコマンドで作成したプロジェクトディレクトリにatomic designを適用して決めました。organismsやmoluculesは将来的に分割が予想されるコンポーネントも配置しています。コンポーネントを分割する際は再利用性がある場合と可読性の向上のための2つの場合に分けて行いました。 reactPortfolio ├── build ├── node_modules ├── package.json ├── public │ └── index.html ├── README.md ├── src │ ├── App.tsx │ ├── assets │ │ ├── data //配列などのデータ格納ディレクトリ │ │ ├── images //画像格納ディレクトリ │ │ ├── styles │ │ │ ├── media.tsx //styled-media-queryのラッパーファイル │ │ │ └── theme.tsx //Material-UI用のカラーテーマファイル │ │ └── Type.tsx │ ├── components │ │ ├── atoms │ │ ├── molecules │ │ ├── organisms │ │ ├── pages │ │ └── templates │ ├── index.tsx │ ├── react-app-env.d.ts │ └── ComponentRouter.tsx //ルーターファイル ├── tsconfig.json ├── types │ └── import-jpg.d.ts └── yarn.lock コーディング規則 型定義 ・関数コンポーネントにはアロー関数を使い、型定義は「VFC」で行う。 ・childrenを使いたい場合は"PropsType"に型定義して使うこと。 ・基本的に関数コンポーネントの返り値に型注釈はつけない。 ・anyは使用禁止。 スタイル ・一行で済むスタイリングも基本的にはstyled-coponentsでスタイルコンポーネントを作成する。 ・スタイルが2行以上に拡張される確率が非常に低いと判断される場合はインラインスタイルを使用してもよい。 ・スタイルコンポーネントは関数コンポーネントの後に記述し、登場するスタイルコンポーネントの順に書く ・レスポンシブ対応はstyled-media-queryを用いて行い、レスポンシブ対応しているcssプロパティは下の部分に寄せて改行する。 命名規則 ・スタイルコンポーネントの名前は"S + キャメルケースの名称"とする。 ・複数要素を囲うタグの名前は”意味を推測しやすい名前 + Container”とする。"Wrapper"は混乱を避けるため利用しない。 ・コンポーネント全体を囲うタグの名前は”SComponentContainer”とする。 ・命名は"Container"などを含めて4単語までのキャメルケースで行い、5単語以上になる場合は1単語を省略するか異なる命名を考える。 ・型定義の末尾には"Type"とつける。 ・propsの型名は"PropsType"とする。 その他 ・短絡評価によるコンポーネントの表示、非表示は行わず、三項演算子で実現する。 ・importのエリアはライブラリ、material-uiなどのスタイル、自作コンポーネント、型定義や配列データ、に分けて改行を入れる。 ・将来的に数が大きくなる可能性がある定数配列などはdataフォルダに格納し、インポートして使う。 工夫した点 atomic designによるディレクトリ構成 atomic designを利用することでコンポーネントがどのように利用されるのかが分かりやすくなり、可読性も向上しました。 コーディング規則による統一性 自分以外の人間がコーディングをしたとしても同じようなコーディングになるように自分なりに規則を決めてコーディングしました。 styled-media-queryを用いたレスポンシブ対応 そのまま記述することも考えましたが、ブレイクポイントを数値で書くのは非常に危険だと考え、別ファイルに書いてインポートするなども考えましたが少し手間でした。何か良いライブラリがないかと探した際にstyled-media-queryを見つけましたが、そもそもの記述が少し冗長だったのでラップして短く、安全にレスポンシブ対応を行うことが出来ました。今回のポートフォリオではブレイクポイントを1170pxと768pxの2つに設定してレスポンシブ対応を行っています。 //そのままのstyled-media-query const SText = styled.h1` font-size: 64px; ${media.between("medium","large")` font-size: 36px; `} ${media.lessThan("medium")` font-size: 26px; `} `; //ラップして簡略化したもの const SText = styled.h1` font-size: 64px; ${media.lg` font-size: 36px; `} ${media.md` font-size: 26px; `} `; 簡潔で分かりやすいデザイン Material-UIやreact-vertical-timeline-componentを利用した簡潔で分かりやすいデザインを心掛けました。 反省点 レスポンシブ対応がモバイルファーストでない モバイルファーストで設計した方が良いことは知っていたのですが、具体的にどうすれば良いのかわからずPCをベースにスタイリングしていった結果、あとから大幅な修正をすることになりました。 おわりに モダンな技術を用いてポートフォリオサイトを作成しました。作ってみないと分からないことがたくさんあったので良い経験になりました。次はサーバーサイドの技術を含めた作品を作りたいと思います。 参考文献
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

独学でタスク管理サービスFroteをポートフォリオとして開発した

はじめに 現在情報系の大学院1年生のつむぎといいます。web業界に行きたいと思い、フロントエンジニアのポートフォリオとしてタスク管理サービスFroteを独学で開発しました。まだ完成とは程遠いですが、今回はとりあえずサービスが公開出来るまでの過程を書いていきたいと思います。作成したものはこちらです[Frote] [github] 開発しようと思った背景 予算的、技術的に一般ユーザーが満足するクオリティのものは作れないと思ったので、自分が欲しいものを作ろうと決めました。毎日のタスクをvscodeのテキストファイルで管理していたのですが、問題点が大きくわけて2つありました。1つは依存関係のあるタスク同士が分かりにくいという問題です。Aが終わらないとBが出来ない状態を「BはAに依存している」と定義するとAとBは並列の関係にあるべきではありません。つまり、AのほうがBより優先度は高いですが、あたかも同じ程度の優先度に見えてしまっていました。2つ目は優先度の決定に時間がかかるという問題です。依存関係も気にしつつ、こちらのほうが優先度が高いななどと判断する必要がありました。後からタスクを追加する場合もどこに入れようかなどで悩み、結果として時間がかかっていました。 この2つの問題点を解決できるようなtodoアプリは僕が探した感じは見つからなかったので、僕が作ろうと考えた次第です。Frote(フローテ)はFree priorityからフランス語のprioriteを混ぜて命名しました。 開始時のスキル 大学でCとDBをがっつりとJavaを少し、あとはatcoderでC++を趣味程度で触っているくらいしか知識がありませんでした。html,css,javascriptはhello worldが出来るレベル。 要件定義 ・自分の技術力をアピール出来るようなもの ・タスクの依存関係の可視化、優先度の自動決定が出来るタスク管理サービス ・お金は極力かけない ・時間の関係上学習コストは出来る限り少なくしたい ・レスポンシブ対応 技術選定 React 今の流行り的にSPAはやりたいと思い、採用しました。 TypeScript C言語をやっていたせいか静的型付言語っぽい方が好きなので採用しました。 styled-components コンポーネント志向と相性の良いCSS in JSの中で有名なのを採用しました。tailwindcssなども考えましたが、最初は生のcssを触りたかったのでこちらにしました。 material-ui reactのUIコンポーネントライブラリとして定番なものを選びました。 recoil 状態管理はrecoilでやっています。最初はuseContextでやっていたのですが、大変だったので移行しました。 Laravel(php) バックエンド言語は悩みましたがphpにしました。nodejsとGOは最初に触るのには不安がありましたし、railsはSPAが得意そうな印象があまり無かったです。スクレイピングなどもする予定が無かったので、phpと一番人気のフレームワークlaravelを採用しました。 heroku 本当はAWSにしたかったのですが、費用と学習コストを考えてherokuにデプロイすることにしました。 mySQL スタンダードなものを採用しました その他使用技術 react-roter,react-hook-form,styled-media-query,vscode,prettier,npm,webpack, Babel,Composer,Git,GitHub DockerやCircle CI、nextjsなども使いたかったのですが、一度に手を出しすぎると大変そうだったので今回は断念しました。 基本設計 優先度の決定 パラメータなしはきついので、緊急度と重要度というパラメータをタスク追加時に決めてもらう。 依存関係の可視化 依存関係のあるタスクはリスト構造で保存することにし、依存関係のあるタスクの集まりを「リスト」と呼ぶ。 タスクのグループ化 タスクがグループ化出来るようにグループも作る。 タスクの挿入と追加 リストへの挿入、追加機能を作成する。また、入力フォームも動的フォームである必要がある。 認証機能 laravelの機能を使ったクッキーベースの認証を行う。認証情報自体はAPIで取得する。 データベース設計 ER-図など書こうと思ったのですが、思ったより時間かかりそうだったのでテキストで説明します。 tasksテーブル id(primary) task_list_id(foreign) task order timestamps task_listsテーブル id(primary) group_id(foreign) user_id(foreign) importance urgency timestamps groupsテーブル id(primary) user_id(foreign) group usersテーブル id(primary) name email email_verified_at password remember_token created_at update_at usersテーブルはlaravelのテンプレートで生成されるものを使用しています。このサービスの基本単位はリストであり、リストに1つ以上のタスクが存在します。挿入などのためにtasksテーブルはorderカラムを持っています。 工夫した点 ・TypeSctiptの恩恵を受けるためanyはほとんど使用しなかった ・コンポーネント志向を意識し、切り出せる部分は切り出して使いまわした ・styled-media-queryで作成した2つのブレイクポイントを使用しレスポンシブ対応にした ・ローディング時用のUIを用意(一部) ・入力フォームにて簡単なバリデーションを実施 ・atomicデザインを使用した分かりやすいディレクトリ構造 ・動的フォームの実装 改善が必要な点 ・再レンダリングへの最適化がいまいち ・Promiseへの理解が足りない ・api処理の切り出しがうまく出来ていない ・結果として同じロジックが書かれている部分がある ・見た目とロジックが分離出来ていない おわりに 想像していた倍時間がかかりましたが、自分が思っている機能の半分くらいは実現できました。タスクの停止機能や、別の表示方法などやりたかったことはいっぱいあったのですが、期限内に終わらせることも大切だなと感じました。まだサービスとしてはバグが多すぎるので、これからどんどん改善していきたいと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

styled-componentsで入力補完を効かせる方法(vscode)

Qiita初投稿です。 テスト投稿も兼ねて。 結論: 拡張機能 「vscode-styled-components」 をインストールする。 こちらの方法がおそらく一番手っ取り早いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む