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

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)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ReactにCarbon Design SystemのUIを導入してみた

はじめに

Carbon Design Systemをあまり聞いたことが無い方が多いと思いますが、IBMのオープンデザインシステムです。
Carbon Design System公式

こういった角張った?特徴的なデザインです。(キャプチャは公式サイトより)
image.png

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.js
import './index.scss';
  • client/app-name/ App.css -> App.scssにリネーム(せっかくなので。やらなくても良い)

これで準備完了。動作確認をします。
↓を参考にヘッダーを付けてみます。
https://www.carbondesignsystem.com/components/UI-shell-header/usage

  • App.jsを修正
App.js
import 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;

このような表示がされれば成功。それっぽい画面になりました。
image.png

参考サイト

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

Next.jsでクエリパラメータを遷移先に渡すにはどうすればいいのか?

Next.jsでクエリパラメータを渡す方法について日本語の記事が少ないので、この記事では「Next.jsでどのようにしてクエリパラメータを渡すのか?」について解説します。

まず、サンプルで作る画面は以下の通りです。
Nextjsのパラメータ引き渡し.gif
大まかに説明するとホーム画面(index.jsx)で入力した内容を出力画面(output.jsx)で出力しています。

ホーム画面

WS000005.JPG

index.jsx
import { 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に入力した値をセットしています。

出力画面

WS000003.JPG

ouput.jsx
import { 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となり、空白で表示されます。
WS000004.JPG

まとめ

  • useRouterフックを使ってrouter.pushpathname(遷移先)query(渡すパラメータ)をセットする。
  • 遷移先では、router.query.「パラメータ名」で出力できる
  • 呼び出し元でパラメータが設定されていなければ、{}で渡される
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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.js
export 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 uiConfigsigninOptionsまではセットでしか使えないみたいです。

SignIn.jsx
import 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つが並びます。
スクリーンショット 2020-11-27 14.58.55.png

今回コメントアウトしてあるプロバイダーもここに並べれば表示だけはされたので(必要なら)認証をとってFirebaseの設定を有効にするだけで使用できるはずです。

4.Reduxで状態管理する為、必要な情報を見てみる

ここからFluxに基づいて初期stateの項目を管理すべくまずはconsole.log(result)で見てみるが何も返ってこない・・・
加えてEmail認証ではEmailの入力欄しか無いことに気づく(パスワード設定はできないみたい:これもカスタマイズできんのか?)
uiConfig内の項目はごちゃごちゃイジれないみたいなので(というか分からない)今回諦めて別の方法で実装する必要がありそうだと言うことだけは分かった。
・なんかモバイル(Andoroid)では各Providerごとにカスタマイズが効くみたいな記事は見かけましたが、Reactでは無理なのか・・・

最後に

・この3ファイルのみでログインが実装できるのは驚きだが、自分の意図したとおりに組むのにはまだまだスキル不足が否めない
→学習に余裕ができたらカスタマイズに関して(できるのかできないのかも含め)調べてみたいと思う。

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

【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.js
import 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 Button

Button.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.js
import 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>


上記ソースコードを実際に出力するとこのようになると思います。

storybook

  • Button.jsで左のサイドバーの親となるButtonの作成。
  • Button.stories.jsでその子となるコンポーネントを記述。
  • Button.cssでそれぞれの見た目を記述。


終わりに

簡単な導入方法と1例の紹介でした!
さらに掘り下げる場合は公式サイトなどを見てみると良いと思います!

Storybook の公式ドキュメント

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

【動画版】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」の検証を書こうかな。
 
 

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

【無料】 最新の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すらも使いこなせていないのにそれらを使おうとしても、最大限の機能を使うことはできないと思います。なので、地道にコツコツ頑張りましょう。

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

Two ways to trigger event in react component.

Extend react.Component class

  1. 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

  1. 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>
    );
};
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【TypeScript】Objectのkeyによってvalueの型を推論するテクニック

:question: 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;
}

:star2: Solution

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ならサジェストも出ます
スクリーンショット 2020-11-26 21.57.32.png

:pencil: Demo

See the Pen Demo: change object value type by key by mikan3rd (@mikan3rd) on CodePen.

↑ Code SandboxはQiitaに埋め込みできないようなのでCodePenを埋め込んであります
(ただしCodePenではType Errorなどは出ません・・・)

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

Next.jsでパスパラメータを取得する方法

概要

フロントエンドのフレームワークを使うと、パスパラメータを使用したくなる時があります。パスパラメータについては、パスパラメータとクエリパラメータの違いを参照頂きたいのですが、URLパスに変数の値を指定する手法です。これをNext.jsで実現したい場合、どうすれば良いのか今回書きます。

どうすれば良いのか

ドキュメントの動的なルーティングに書いてあるとおり、パスパラメータを設定したいパスのjsファイル名に[パスパラメータ名].jsを指定することで、パラメータの取得をそのjs内で行うことができます。言葉だけだと、ピンと来ないかもしれないので以下にサンプルを示します。

実装サンプル

今回は記事投稿を例にします。パスパラメータに投稿id(post_id)を設定し、これを取得するやり方を書きます。

<ファイルの配置>
pages/postの配下に[post_id].jsを配置します。
スクリーンショット 2020-11-27 0.19.43.png

<[post_id].jsの内容>
router.queryでパスパラメータ名(post_id)を指定することで取得できます。

[post_id].js
import { 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-27 1.50.17.png

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

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をいちいち一つ一つ開けないと中身がみれないので不便です。

スクリーンショット 2020-11-27 0.26.37.png

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つのリストが表示されていることと直感的にも合います。
スクリーンショット 2020-11-27 0.32.56.png

結論

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

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