- 投稿日:2020-11-27T17:51:48+09:00
TypeScript入門
特徴
- 型定義が使える(変数, 引数、返り値、オブジェクト)
- インターフェース、クラス
- 入力補完(vs codeなど)
例
変数の定義
let name: string; // name を文字列型として宣言 name = "ebihara"; name = 0; // エラー: 文字列ではない // 直接代入 const name: string = "hogehoge"変数の定義(配列)
const array: string[] = []; array.push("ebihara"); array.push(1); // エラー:配列の型と合わない // 直接代入 const array: string[] = ["hogehoge", "fugafuga"];クリーンアーキテクチャ
- 層を分けて実装していくことで仕様変更に強くなる(必要な奏の部分だけの修正でいい)
- 層→Presentation Layer(UIなど)、Domain Layer(UseCasesなどビジネスロジック), Data Layer(entity定義など)
ex.
- page(Presentation Layer)
- EmployeeUseCase(Domain Layer)
- repositoryやdomain(Data Layer)
- 投稿日:2020-11-27T17:08:47+09:00
ReactにCarbon Design SystemのUIを導入してみた
はじめに
Carbon Design Systemをあまり聞いたことが無い方が多いと思いますが、IBMのオープンデザインシステムです。
Carbon Design System公式こういった角張った?特徴的なデザインです。(キャプチャは公式サイトより)
React、Vue、AngularといったメジャーなUIフレームワークで利用することが出来ます。
今回、関わっているプロジェクトでCarbon Design Systemを使ったUIを作ることになったので導入手順、動作確認までの手順をまとめてます。環境
- Windows 10
- Node.js v12.16.3
- npm 6.14.4
- yarn 1.22.4
手順
- ディレクトリ作成
# アプリのコードを管理するディレクトリを作成 mkdir app cd app # クライアントのコードを配置するディレクトリを作成 mkdir client
- Carbon Design Componentの導入
cd client npx create-react-app my-app ※my-app=アプリ名 ※npxはnpm 5.2 から利用できるパッケージランナーツール cd my-app yarn add carbon-components carbon-components-reac @carbon/icons-react carbon-icons --save # scssを使うために必要 バージョンを指定してインストールする yarn add node-sass@4.14.1 --save
- client/app-name/ にindex.scssを作成
index.scss@import 'carbon-components/scss/globals/scss/styles.scss';
- index.jsをindex.scssを読み込むように修正
index.jsimport './index.scss';
- client/app-name/ App.css -> App.scssにリネーム(せっかくなので。やらなくても良い)
これで準備完了。動作確認をします。
↓を参考にヘッダーを付けてみます。
https://www.carbondesignsystem.com/components/UI-shell-header/usage
- App.jsを修正
App.jsimport React from "react"; import { render } from "react-dom"; import Search20 from "@carbon/icons-react/lib/search/20"; import Notification20 from "@carbon/icons-react/lib/notification/20"; import AppSwitcher20 from "@carbon/icons-react/lib/app-switcher/20"; import { Header, HeaderName, HeaderGlobalAction, HeaderGlobalBar, HeaderNavigation, HeaderMenu, HeaderMenuItem } from "carbon-components-react/lib/components/UIShell"; import { Button } from 'carbon-components-react'; import './App.scss'; function App() { return ( <div className="App"> <div className="container"> <Header aria-label="IBM Platform Name"> <HeaderName href="#" prefix="IBM"> [Platform] </HeaderName> <HeaderNavigation aria-label="IBM [Platform]"> <HeaderMenuItem href="#">Link 1</HeaderMenuItem> <HeaderMenuItem href="#">Link 2</HeaderMenuItem> <HeaderMenuItem href="#">Link 3</HeaderMenuItem> <HeaderMenu aria-label="Link 4" menuLinkName="Link 4"> <HeaderMenuItem href="#">Sub-link 1</HeaderMenuItem> <HeaderMenuItem href="#">Sub-link 2</HeaderMenuItem> <HeaderMenuItem href="#">Sub-link 3</HeaderMenuItem> </HeaderMenu> </HeaderNavigation> <HeaderGlobalBar> <HeaderGlobalAction aria-label="Search" onClick={() => {}}> <Search20 /> </HeaderGlobalAction> <HeaderGlobalAction aria-label="Notifications" onClick={() => {}}> <Notification20 /> </HeaderGlobalAction> <HeaderGlobalAction aria-label="App Switcher" onClick={() => {}}> <AppSwitcher20 /> </HeaderGlobalAction> </HeaderGlobalBar> </Header> </div> </div> ); } export default App;参考サイト
- 投稿日:2020-11-27T16:05:29+09:00
Next.jsでクエリパラメータを遷移先に渡すにはどうすればいいのか?
Next.jsでクエリパラメータを渡す方法について日本語の記事が少ないので、この記事では「Next.jsでどのようにしてクエリパラメータを渡すのか?」について解説します。
まず、サンプルで作る画面は以下の通りです。
大まかに説明するとホーム画面(index.jsx)で入力した内容を出力画面(output.jsx)で出力しています。ホーム画面
index.jsximport { useRouter } from 'next/router'; import {useState} from 'react'; export default function Index() { const router = useRouter(); //ルーターの取得 const [input, setInput] = useState(); // ボタンをクリックしたときの処理 const clickButton = () => { //未入力の時 if (!input) { return; } router.push({ pathname:"/output", //URL query: {input :input} //検索クエリ }); } return ( <div style={{textAlign: "center", marginTop: "50px"}}> {/* 入力項目 */} <input type="text" value={input} onChange={(e) => setInput(e.target.value)} /*変更時inputに値をセット*/ /> {/* ボタン */} <button onClick={clickButton} disabled={!input}> {/*入力項目が未入力の場合、非活性*/} 遷移 </button> </div> ) }ホーム画面では、入力内容を出力画面に渡して画面遷移を行っています。大きく分けると2ステップです。
まず最初に、
useRouter
フックを使うためにインポートが必要です。
import { useRouter } from 'next/router';
次に
router
オブジェクトのpush
を使って画面遷移を行っています。このとき、クライアントサイドでの遷移となり、サーバーからリクエストが返されるわけではないので注意が必要です。そして、オプションに以下の設定を行います。
・pathname:遷移する先のURL
・query:遷移先に渡すパラメータこれにより「遷移先」、「遷移先に渡すパラメータ」がセットされます。注意点としてはqueryはオブジェクト型で渡すことです。そのため文字列をそのまま渡すのではなく、連想配列で渡します。
今回の場合は、
input
に入力した値をセットしています。出力画面
ouput.jsximport { useRouter } from 'next/router'; export default function Output() { const router = useRouter(); return ( <div style={{textAlign: "center", marginTop: "50px"}}> {/* パラメータの表示 */} <h1>input:{router.query.input}</h1> </div> ) }出力画面では渡ってきたパラメータを表示するだけです。
routerオブジェクトの
query
にパラメータが入っているので、router.query.input
で取得できます。ちなみに、遷移元でパラメータが設定されていない場合、
{}
で渡ってくるので先ほどの値はundefined
となり、空白で表示されます。
まとめ
useRouter
フックを使ってrouter.push
にpathname(遷移先)
、query(渡すパラメータ)
をセットする。- 遷移先では、
router.query.「パラメータ名」
で出力できる- 呼び出し元でパラメータが設定されていなければ、
{}
で渡される
- 投稿日:2020-11-27T15:34:33+09:00
FirebaseUIでAuth認証ログインをRedux管理しようとして失敗した件(Google,Twitterログイン)
最初に…
現在学習中のReactReduxでFirebaseUIを使用して作ろうとしたAuth認証。
がしかしこれは失敗談です(やり方はあるのかも?)結論:Reduxを使用してHomeにログイン情報の表示ができませんでした。
FirebaseUIを使用すると簡単に実装できますが、細かい設定をするとなると向かないのかな?と感じてしまいました。
やり方があれば知りたいのでどなたかご意見下さると幸いです。
合わせてご指摘事項等ありましたらご連絡頂けますとありがたいです。環境構築
0. $ npx-create-react-app (projectname)
1.$ npm install
--save firebase
history@4.10.1
firebaseui --save
2. firebaseコンソールでの初期設定(詳細は割愛)
3. $ firebase init (初期化各種項目は割愛)※2.のhistoryは、後々pushメソッドをVer.5.0.0で使用するとエラーが出るので予め対策
→Uncaught Could not find router reducer in state tree, it must be mounted under "router"1.Firebaseコンソール(Web)でAuthenticationの設定
・firebaseのプロジェクト画面(コンソール)を開いてメニューからAuthenticationをクリックして有効にする
・今回はメール,google,Twitter認証の3つでの実装をしてみる
・Teitterの認証取得は「Twitter 開発者 申請」で入力すれば出てくるので割愛します。
→因みに皆さん英語で申請されている様ですが日本語でも申請通るみたいですね。
→Twitterに関しては有効にした後にコールバックURLをTwitterデベロッパーのプロジェクトページの欄に入力する必要がある2.認証情報ファイルの作成
・コンソール画面の設定アイコン(歯車の)から設定画面に入る
・マイアプリの”Firebase SDK snippet”の項目の構成にチェックを入れてスクリプトをコピーする(以下の内容が記述されたものをコピーできる)
・作業ディレクトリに戻り、src
配下にfirebaseディレクトリを作成し以下のconfig.js
(公式ドキュメントにもある)とエントリーポイントのindex.js
を作成する
・こういった情報は.envの方がいい?(他の記事見てるとそのやり方も見かけますが)とりあえずgitignoreには記載します。。。config.jsexport const firebaseConfig = { apiKey: "API_KEY", authDomain: "PROJECT_ID.firebaseapp.com", databaseURL: "https://PROJECT_ID.firebaseio.com", projectId: "PROJECT_ID", storageBucket: "PROJECT_ID.appspot.com", messagingSenderId: "SENDER_ID", appId: "APP_ID", measurementId: "G-MEASUREMENT_ID", };以下は今回使用するサービスのみ記述する
index.js// 以下は今回使用するfirebaseのサービス(一つずつ記述が必要) import firebase from "firebase/app"; import "firebase/auth"; import "firebase/firestore"; import { firebaseConfig } from "./config"; //先に作成したconfig.jsの読み込み export const providerGoogle = new firebase.auth.GoogleAuthProvider(); //使用するプロバイダー名で定数化 export const providerTwitter = new firebase.auth.TwitterAuthProvider(); //使用するプロバイダー名で定数化 export const firebaseApp = firebase.initializeApp(firebaseConfig); //コピーした設定を使ってアプリケーションの初期化を実施することでアプリ内でfirebaseのサービスが使えるようになる //以下は毎回firebase.hoge()とメソッドを入力するのが面倒なので最初にそれぞれのメソッドに対し定数化しておく export const auth = firebase.auth(); export const db = firebase.firestore(); export const FirebaseTimestamp = firebase.firestore.Timestamp; //データベースのデータ作成日時を記録しておけるもの(サーバーからタイムスタンプを取得して記録する) export default firebase;3.認証ログインページの作成の作成
簡単に実装するならFirebaseUIがいいというのを見かけ試してみました。
const uiConfig
〜signinOptions
まではセットでしか使えないみたいです。SignIn.jsximport React from "react"; import firebase from "../firebase/index"; import StyledFirebaseAuth from "react-firebaseui/StyledFirebaseAuth"; const uiConfig = { signInFlow: "popup", signInSuccessUrl: "/", signInOptions: [ firebase.auth.GoogleAuthProvider.PROVIDER_ID, firebase.auth.TwitterAuthProvider.PROVIDER_ID, firebase.auth.EmailAuthProvider.PROVIDER_ID, //firebase.auth.FacebookAuthProvider.PROVIDER_ID, //firebase.auth.GithubAuthProvider.PROVIDER_ID, //firebase.auth.PhoneAuthProvider.PROVIDER_ID ], }; const SignIn = () => { return ( <div> <StyledFirebaseAuth uiConfig={uiConfig} firebaseAuth={firebase.auth()} /> </div> ); }; export default SignIn;使用する各プロバイダーのアイコンはどこから来てるの?と思えますが、
<StyledFirebaseAuth>
にsignInOptions
のプロバイダーが入ってくると、FirebaseUIが効いてそれぞれ記述したプロバイダー(今回は:Google、Twitter、Email)認証の3つが並びます。
今回コメントアウトしてあるプロバイダーもここに並べれば表示だけはされたので(必要なら)認証をとってFirebaseの設定を有効にするだけで使用できるはずです。
4.Reduxで状態管理する為、必要な情報を見てみる
ここからFluxに基づいて初期stateの項目を管理すべくまずは
console.log(result)
で見てみるが何も返ってこない・・・
加えてEmail認証ではEmailの入力欄しか無いことに気づく(パスワード設定はできないみたい:これもカスタマイズできんのか?)
uiConfig
内の項目はごちゃごちゃイジれないみたいなので(というか分からない)今回諦めて別の方法で実装する必要がありそうだと言うことだけは分かった。
・なんかモバイル(Andoroid)では各Providerごとにカスタマイズが効くみたいな記事は見かけましたが、Reactでは無理なのか・・・最後に
・この3ファイルのみでログインが実装できるのは驚きだが、自分の意図したとおりに組むのにはまだまだスキル不足が否めない
→学習に余裕ができたらカスタマイズに関して(できるのかできないのかも含め)調べてみたいと思う。
- 投稿日:2020-11-27T14:53:39+09:00
【React】React Storybook v.6 導入 サンプル
はじめに
"React Storybook" の導入について簡単にまとめたメモとして残します。
Storybook とは
Storybook を使用することで、UI コンポーネントをビジネスロジックやコンテキストから切り離して開発できるようになります。また可視化することができるので提案、打ち合わせなどにも活用できます。
はじめ方
さっそくですがまずは、Reactのアプリケーションを作成します。
npx create-react-app React-Story-Book
RCAで作成したアプリにStorybookを追加します。
npx -p @storybook/cli sb initコマンドの実行には基本的に yarn となりますが、 yarn ではなく npm を使用したい場合には、上記のコマンドの末尾に
--use-npm
つけることで、npmコマンドを使用することができます。
(今回は--use-npm
をつけてnpmで実行しました)
処理が完了したら下記コマンドを実行します。
npm run storybookこれでポート 9009でStorybookのデフォルトのエクスプローラーが表示されたと思います?
簡単なボタンの作成
最後に簡単なボタンコンポーネントの例を作っていきたいと思います。
準備
上記コマンドによりjsonファイルに各Storybookの追加された記述と
アプリケーションフォルダ内にstorybookディレクトリとsrcディレクトリ直下にstoryディレクトリが作成されているのが確認してください。今回は新たにディレクトリを作成していくので、src直下のstoryディレクトリを削除します。
srcディレクトリ直下にcomponentsディレクトリを作成してさらにButtonディレクトリを作成し、その中に以下3つのファイルを作成します。
・Button.js
・Button.stories.js
・Button.css
ソースコード
Button.js
Button.jsimport React from 'react'; import './Button.css' function Button(props) { const { variant = 'primary', children, ...rest} = props return ( <button className={`button ${variant}`} {...rest} > { children } </button> ) } export default ButtonButton.css
Button.css.button { border: none; color: white; padding: 15px 32px; text-align: center; text-decoration: none; display: inline-block; font-size: 16px; border-radius: 4px; cursor: pointer; } .primary {background-color: #008CBA;} .secondary {background-color: #e7e7e7; color: black;} .succcess {background-color: #4CAF50;} .danger {background-color: #f44336;}Button.stories.js
Button.stories.jsimport React from 'react'; import Button from './Button'; export default { title: 'Button', component: Button } export const Primary = () => <Button variant='primary'>Primary</Button> export const Secondary = () => <Button variant='secondary'>Secondary</Button> export const Succcess = () => <Button variant='succcess'>Succcess</Button> export const Danger = () => <Button variant='danger'>Danger</Button>
上記ソースコードを実際に出力するとこのようになると思います。
- Button.jsで左のサイドバーの親となるButtonの作成。
- Button.stories.jsでその子となるコンポーネントを記述。
- Button.cssでそれぞれの見た目を記述。
終わりに
簡単な導入方法と1例の紹介でした!
さらに掘り下げる場合は公式サイトなどを見てみると良いと思います!
- 投稿日:2020-11-27T13:34:39+09:00
【動画版】if (hoge) {~ 比較演算子を使わないIF文がどこまでを「true」とするのかを徹底的に検証してみた*JavaScript
前提
if (text) { return true } return false
この書き方がどの時が「true」で
どの時に「false」を返すのか
を検証。
そして、動画にしてみた記事である。
*********************
前回の記事はテキスト版として掲載している。
動画で分かりづらかったらコチラ検証環境
・フレームワーク:React.js
※少なくともJavaScript系の言語は同じ結果だと思う。
・コード// この変数にいろんな物を入れてみることで検証 let text = 'hoge' const result = () => { // ↓ここの判定具合を検証する if (text) { console.log('text:', text, true) // 条件一致 return text + ' ←textの中身' } console.log('text:', text, false) // 条件不一致 return 'textになんも入ってないで' } function App() { return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <p>{result()}</p> {/* ←ここで画面に表示 */} </header> <div></div> </div> ); } export default App;
では今回は動画で検証開始!!!!!!!!
※音声あるのでご注意を
まとめ
動画作るのは結構エネルギー使うので、
たまにでいいと思った。
次回はテキスト版で、
「length」の検証を書こうかな。
- 投稿日:2020-11-27T11:52:49+09:00
【無料】 最新のReactの書き方を何で勉強するべきか?
この記事の対象者
- プログラミングをある程度できてReactを勉強してみたい人
- React の最新の書き方を知りたい人
- React の学習を何でするべきか悩んでいる人
React の新しい書き方とは?
主にReact Hooksのことを指しています。
反対に古い書き方はクラスコンポーネント、componentWillMountなどのコンポーネントのライフサイクルを使用しているものです。Hooksは2019年2月に追加されたのでもうすでに1年以上経過していますし、基本的にはHooksを使用することを公式が推奨しています。
React 公式サイトにも載っていますが、クラスコンポーネントではステートフルなロジックの再利用が難しく、記述も関数コンポーネントに比べて長くなりがちで可読性が低いです。
そのため、これからReactを学ぼうと考えている人は絶対に、React Hooksを学んでおきましょう!
どうやって勉強するの?
ずばり、Youtubeで学びましょう。
Youtubeのメリット
- ハンズオン形式で学べる。
- プログラミングの言語知識だけでなく役立つサイト・裏技も学べる。(ショートカット、API、命名規則など)
- Udemyと比べても大差ないレベル感のものが多い。
- 英語も一緒に勉強できる。(後々ドキュメントを読むときに役立つ)
- ほとんど最新のバージョンを使って、最新の記法で書いてくれている。
Youtubeのデメリット
- 基本的に英語圏しかない。
- 再生時間が長くなりがちで、短時間での勉強には向いていない。
- 自分が知りたい情報にたどり着くのに時間がかかる。一応、メリット、デメリットを挙げてみましたけど、書籍などはどうしても公式チュートリアルをなぞったような堅い書き方が多いですし、Udemyはお金がかかるし、Progateなどは実務とはかけ離れすぎているし、基本的には「Youtubeを使わない手はない!」と思っています。
Youtubeでのプログラミング勉強法
これはReact以外の言語においても使える方法なので、ぜひ時間のある方は試してほしいです!今回はReactで説明していきます。
STEP1 言語名 + Tutorial で検索する
まず、自分が勉強したい、言語・フレームワーク・ライブラリを打ってその後にTutorialと入れて検索してみましょう。
「React Tutorial」で検索してみましょう。
チュートリアル動画は、基本的な構成としては、言語の簡単な解説、環境構築、Hello World、各機能の解説、簡単なアプリの作成、というものが多いです。再生時間としては3時間以上が基本ですかね。
STEP2「1年以内 + 公式 or 再生数が多い 」動画を探す
一番重要なのはいつ公開されたかです。
自分がおススメしているのはYoutubeの並べ替えでアップロード順にして、再生数が1000回以上の動画もしくは、公式マークがついているチャンネルの動画、再生時間が2,3時間以上の動画をチェックする方法です。
再生回数が多い、公式マークがついているチャンネル、再生時間が3時間以上の動画は、基本的に内容も充実しており、スライドを使って説明していたり、機能を一つ一つコメントアウトして説明してくれたりしていて良質なものが多いです。
あとは、少しやってみて自分の肌に合うものを確かめて、どんどん進めていきましょう!
ちなみに現在おすすめの「React Tutorial」動画としては以下になります。
Coding Addict
公開日:2020/9/29
再生時間:10時間
説明:ソースコードが公開されており、Hooksの機能も丁寧に解説している。Bitfumes
公開日:2020/9/21
再生時間:10時間
説明:画像検索サービスを作りながら、Reactの基礎を学べてNetlifyでデプロイも行う。codedamn
公開日:2020/8/27
再生時間:9時間
説明:連絡先登録と検索ができるサービスを作れる。STEP3 クローンアプリを作る
Udemyなんかでもよくありますが、Youtube、Instagram、Amazon、Twitter、Netflixのクローンアプリを作りましょう。クローンアプリなんて作って意味あるの?って思う人もいるかもしれませんが、実際のサービスを作るために、どういう風に実装しているのかそのためにどういうサービスを使っているのかなどを学ぶことができ、大変参考になります。
セキュリティに関してもパスワードやセッションの保存方法、ユーザーのデータモデルの設計など自分一人で一から考えていると、それだけで1週間以上かかってしまうこともあります。そのため、デフォルトスタンダードとまではいかないにしても、基本的なサービスの作り方を学んでいくと自分でこんな機能を実装したい!と思ったときに、あのサービスのこの機能とこの機能を組み合わせれば作れるじゃないか?という風に自走力が身につきます。
STEP4 オリジナルアプリを作る
クローンアプリにオリジナル機能を一つ追加するだけでも良いです!
思いついたら即行動の精神で作ってみてください!さいごに
Reactを勉強する上で、Next.jsとかGatsbyとかに手を出したくなる気持ちはすごくわかるんですが、結局、素のReactすらも使いこなせていないのにそれらを使おうとしても、最大限の機能を使うことはできないと思います。なので、地道にコツコツ頑張りましょう。
- 投稿日:2020-11-27T09:08:56+09:00
Two ways to trigger event in react component.
Extend react.Component class
- Use bind(this)
import * as React from 'react'; export interface TempProps { title: string; onButtonClick: (v: string) => void; } export class TempComponent extends React.Component<TempProps> { public componentDidMount() { this.handleOnButtonClick = this.handleOnButtonClick.bind(this); } public render() { return ( <div> <button onClick={this.handleOnButtonClick}>aaaa</button> </div> ); } private handleOnButtonClick() { this.props.onButtonClick(this.props.title); } }2.Use arrow method()=>{}
import * as React from 'react'; export interface TempProps { title: string; onButtonClick: (v: string) => void; } export class TempComponent extends React.Component<TempProps> { public render() { return ( <div> <button onClick={_ => this.handleOnButtonClick()}>aaaa</button> </div> ); } private handleOnButtonClick() { this.props.onButtonClick(this.props.title); } }Use hook
- Use arrow method
import * as React from 'react'; export interface TempProps { title: string; onButtonClick: (v: string) => void; } export const TempComponent: React.FC<TempProps> = ({ title, onButtonClick }) => { const handleOnButtonClick = () => { onButtonClick(title); }; return ( <div> <button onClick={handleOnButtonClick}>aaaa</button> </div> ); };2.Without using bing this, it also works in react hook.
import * as React from 'react'; export interface TempProps { title: string; onButtonClick: (v: string) => void; } export const TempComponent: React.FC<TempProps> = ({ title, onButtonClick }) => { function handleOnButtonClick() { onButtonClick(title); }; return ( <div> <button onClick={handleOnButtonClick}>aaaa</button> </div> ); };
- 投稿日:2020-11-27T08:42:43+09:00
【TypeScript】Objectのkeyによってvalueの型を推論するテクニック
Problem
次の関数
changeValueByKey
ようにObjectのkeyによってvalueを変更する関数を型安全に作りたい!type State = { text: string; isActive: boolean; }; let state: State = { text: "", isActive: false } const changeText = (value: string) => { // OK state['text'] = value; } const changeIsActive = (value: boolean) => { // OK state['isActive'] = value; } const changeValueByKey = (key: 'text' | 'isActive', value: string | boolean) => { // Type Error state[key] = value; }Solution
- こちらのStack Overflowを参考にしました
type State = { text: string; isActive: boolean; }; let state: State = { text: "", isActive: false } const changeValueByKey = <K extends keyof State>(key: K, value: State[K]) => { state[key] = value; } // OK changeValueByKey('text', 'test') changeValueByKey('isActive', true) // Type Error changeValueByKey('text', true) changeValueByKey('isActive', 'test')
- 解説
keyof
を使うことでプロパティ名のtypeを参照することができますkeyof State
でStateのプロパティ名を参照し、それをextends
継承したtypeK
をGenericsとして用意します- 第一引数
key
はプロパティ名なのでそのままK
を使用し、第二引数value
はStateのプロパティK
のvalueの型なのでState[K]
とします- これでkeyは
text | isActive
となり、keyを指定した時にvalueの型が決まるようになります- keyに
text
を指定した時にvalueはState['text']
なのでstring
に、isActive
を指定した時にvalueはState['isActive']
なのでboolean
しか渡せないようになりました- 今すぐ動作を確認してみたい方はこちら
TypeScriptに対応したEditorならサジェストも出ます
Demo
- Reactの
useState
にObjectを入れて実際に使ってみた時のサンプルはこちらSee the Pen Demo: change object value type by key by mikan3rd (@mikan3rd) on CodePen.
↑ Code SandboxはQiitaに埋め込みできないようなのでCodePenを埋め込んであります
(ただしCodePenではType Errorなどは出ません・・・)
- 投稿日:2020-11-27T01:55:32+09:00
Next.jsでパスパラメータを取得する方法
概要
フロントエンドのフレームワークを使うと、パスパラメータを使用したくなる時があります。パスパラメータについては、パスパラメータとクエリパラメータの違いを参照頂きたいのですが、URLパスに変数の値を指定する手法です。これをNext.jsで実現したい場合、どうすれば良いのか今回書きます。
どうすれば良いのか
ドキュメントの動的なルーティングに書いてあるとおり、パスパラメータを設定したいパスのjsファイル名に
[パスパラメータ名].js
を指定することで、パラメータの取得をそのjs内で行うことができます。言葉だけだと、ピンと来ないかもしれないので以下にサンプルを示します。実装サンプル
今回は記事投稿を例にします。パスパラメータに
投稿id(post_id)
を設定し、これを取得するやり方を書きます。<ファイルの配置>
pages/post
の配下に[post_id].jsを配置します。
<[post_id].jsの内容>
router.query
でパスパラメータ名(post_id)を指定することで取得できます。[post_id].jsimport { useRouter } from "next/router"; import Header from "../../components/common/Header"; import PostRefer from "../../components/post/PostRefer"; const Index = () => { const router = useRouter(); // パスパラメータから値を取得 const { post_id } = router.query; return ( <div> <Header /> <PostRefer postId={post_id} /> </div> ); }; export default Index;<このページへのアクセス>
http://localhost:3000/post/[post_id]
へアクセスすると、パスパラメータを取得するページにアクセスします。
- 投稿日:2020-11-27T00:42:48+09:00
Reactでdivdivする問題をReact.Fragmentで解決する
JSXの記法
JSXファイルはreturnに1つのタグしか持てないというルールがあります。
そのため、以下のようにリストを2つ並べようとすると、2つのulタグをreturnが持つことになり、import React, { Component } from 'react'; class App extends Component { render() { return ( <ul> <li>Coke</li> <li>Soda</li> <li>Orange Juice</li> </ul> <ul> <td>Hamburger</td> <td>Fries</td> <td>Salad</td> </ul> ); } } export default App;以下のようにエラーになってしまいます。
Adjacent JSX elements must be wrapped in an enclosing tag余計なdivタグ
これを回避するためによく使われるのは、
以下のようにdivタグで全体を囲って1つの要素を返すようにする記法です。import React, { Component } from 'react'; class App extends Component { render() { return ( <div> <ul> <li>Coke</li> <li>Soda</li> <li>Orange Juice</li> </ul> <ul> <li>Hamburger</li> <li>Fries</li> <li>Salad</li> </ul> </div> ); } } export default App;しかし、この記法だと余計なdivタグが入ってしまいます。実際、開発ツールで確認すると
rootのdiv要素を開いたらさっき書いたdivが出てきてdivdivしちゃってぱっと見づらいですね。
要素が増えてくるとdivをいちいち一つ一つ開けないと中身がみれないので不便です。divタグの代わりにReact.Fragmentを使う
そこで便利なのがdivではなく、React.Fragmentを用いる記法です。
import React, { Component } from 'react'; class App extends Component { render() { return ( <React.Fragment> <ul> <li>Coke</li> <li>Soda</li> <li>Orange Juice</li> </ul> <ul> <li>Hamburger</li> <li>Fries</li> <li>Salad</li> </ul> </React.Fragment> ); } } export default App;React.Fragmentはそれ自体に意味を持たないので、開発ツールでは表示されません。したがって、rootの下にulタグが2つあるのが一目でわかり、画面に2つのリストが表示されていることと直感的にも合います。
結論
JSXのルール(1つしか要素返せない)に従うためだけのdivはReact.Fragmentに変えて可読性を高めよう!
補足
React.Fragmentは1つしか要素返せないJSXのルールに対して、コードの構造を保つために作られたものです。そのため、divタグとは別物です。例えばReact.FragmentにclassNameを指定したり、styleを指定することはできません。そういう使い方をしたいときは普通にdivを使いましょう。
参考
https://ja.reactjs.org/docs/fragments.html
https://stackoverflow.com/questions/49069746/workaround-to-add-classname-to-fragment-in-react