20200914のReactに関する記事は12件です。

Vue.js使いの自分がReact + TypeScriptにコンバートするためにやったこと(まだ途中)

タイトル通りの話で, 今まで2年ちょいVue.js(含むNuxt.js)使いだった自分がReact + TypeScriptの組み合わせを覚えて仕事にしよう!...という目標に向けて何をしたかについてまとめました.

  • React + TypeScriptの組み合わせでちゃんと開発したい&覚えたい人
  • Vue.js等, 他のJavaScriptライブラリ・フレームワークと二刀流を目指している人
  • SPA(Single Page Application)開発をちゃんとやりたい人

の参考になれば幸いです.

なおコードスニペット的なのは一切ないです.

が, これから学習する方の役に立つと嬉しいです.

わたし(shinyorke)のJavaScript/SPA歴

  • 昔から仕事や趣味⚾️開発でJavaScript, JQuery, Bootstrapは触っていました.
  • JavaScriptは自力で調べながらどうにかやれます.
  • 前職でVue.jsを2年近くやったのでSPAについてはそれなりに開発経験あります.
  • Nuxt.jsでゼロベースからSPAを二回ほど実装・ローンチしました.
  • npmとかyarnの意味はわかってます&環境もnvmで切り替えながらやれるレベルなのでそのへんのエコシステム周りは初心者ではないです(強くもないけど).

なお, Vue.jsのときにやったネタはブログにまとめています.

https://shinyorke.hatenablog.com/entry/hello-nuxt-coreui

https://shinyorke.hatenablog.com/entry/vue-django-hateoas

https://shinyorke.hatenablog.com/entry/front-app-and-vuejs

React + TypeScriptになれるまで

やったことを時系列で.

なお, まだ途中です!

Reactの公式チュートリアル

会社のつよつよフロントできるマンたちのオススメだったので素直に乗って写経しました.

https://ja.reactjs.org/tutorial/tutorial.html

ゲーム完成まで楽勝でいきました.

構成とかどういった意味なのか?的なのをチュートリアルと書いたコードを読みながら理解.

ただ, 肝心なComponentのライフサイクルだの状態遷移だのといった所はわかったようなわかんないような?でした.

書籍を写経してSlack(っぽい)アプリを自前で実装する.

ゲームよりも実践的なアプリを作ると慣れるかな?と思い, 昔読んだ書籍をもう一度掘り返しました.

React, Angular, Vue.js, React Nativeを使って学ぶ はじめてのフロントエンド開発

2年ちょっと前の本なのでそのままのコードで動かんやろ...という不安はあったものの, まあ自己解決できるだろっていう謎理論でそのままスタート.

サーバーアプリを作る(写経)

本編のSlack(風)チャット・クライアントアプリを作る前に, 書籍の説明通りチャットのサーバー部分をFirebase + Expressで作りました.

これについては, ほぼ書籍通りの写経で完了. これは意外だった.

唯一, デプロイができなかったぐらいですかね. 無料プランじゃできないぞ的な(おそらく書籍リリース時はできてた).

ただ, デプロイできなくてもローカルサーバーとして立ち上げて開発できたので別に困らなかったです.

ちなみにFirebaseをゼロから使うのは今回がはじめてでした. 思わぬ所で新しい道具を覚えた.

本丸のReact + TypeScript製チャット・クライアント開発

書籍を見ながらゼロから写経しました, 途中動かないとか色々ありました.

特にライブラリのバージョンがきつかった...書籍通りで動かん!と思い,

https://github.com/okachijs/jsframeworkbook/tree/master/3_6_react

こちらのpackage.jsonを見ながら調整.

あとnodeのLTS(12系)じゃダメだったので8系に落として動かしました, この騒動で半日ほどドハマリ.

これはまあしょうがないか...

その後は順調に行きました, 型安全のJavaScriptは精神衛生上すごく良いというのがよくわかった.

これからやりたいこと

Vue.jsで作ったやつをReact + TypeScriptで写経して本格的に慣れるとか, 今いくつか作りたいネタがあるのでそれをReact + TypeScriptでやるとか.

あと, 会社のプロダクトでいくつかReact + TypeScriptあるのでそこにコントリビュートとか考えています!

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

とても簡単なReactの良さが5分以内に分かる例

はじめに

Web開発のフロントエンドがjQueryからReactへ移った技術改革は、「仮想DOM」「DOM操作をしない」「コンポーネント志向」という文脈で持て囃されて語れます。
しかしこれらの何が嬉しいのか?という方も居ると思います。従来の私もそうでした。

今ではこれらの有難みが分かりますが、実際にフロントエンドコーディング自体が想像しづらいと気付きづらいかなとも思います。
そこで今回はReactの感動に気づいてもらうことを目的に、簡素な例を用意しました。

対象読者は、jQueryは使えるがReactは聞いたことがあり、JSXの書き方くらいは知ってるけどメリットがイマイチ...と思っている方です。

注意

・Reactに関わらずAngularやVue等も含めても成り立つのでしょうが、その2つはほとんど書けないので触れておかないことにします。

・細かい部分は端折り雰囲気重視です。

カウンターアプリ

まずは初期値は0で、ボタンを押すと値が増えていくアプリを作りたいと思います。
マークアップから用意していきます。

<!DOCTYPE html>
<html>
  <head>
    <title>Title</title>
    <!-- Required meta tags -->
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1, shrink-to-fit=no"
    />
  </head>
  <body>
    <p id="value"></p>
    <p><button id="increment">Increment</button></p>
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
    <script src="js/index.js"></script>
  </body>
</html>

※小ネタ:VsCodeを使う際にjQueryを含んだ簡単なマークアップテンプレートを用意するには、Bootstrap 4, Font awesome 4, Font Awesome 5 Free & Pro snippets という拡張機能をインストールし、b4-$で入力補完すると手軽に生成できます。

値の表示要素は#value、ボタンは#incrementと決めました。
これを素にJSの処理を書いていきます。

// 初期値は0。それをvalueに表示させる
var value = 0;
$('#value').html(value);

// ボタンをクリックしたら...
$('#increment').on('click', function () {
  value = value + 1; // valueを1増加させて
  $('#value').html(value); // それを表示させる
});

ここでコードを眺めてみましょう。データの操作とDOMへのデータ反映に分かれていますね。
そこで、データ反映を行う部分をそれっぽい関数名にしてみましょう。

var value = 0;
render();

$('#increment').on('click', function () {
  value = value + 1;
  render();
});

function render() {
  $('#value').html(value);
}

こんな感じになりました。今の例では恩恵があるか微妙ですが、valueに相当するものが増えた場合にこれは威力を発揮するでしょう。
ところが、何となくrender()が2箇所に現れていてスッキリしないと思いませんか?
valueの更新を行ったら、自動でDOMにも反映されていて欲しいですね...。

願わくば、

var value = 0;
render();

$('#increment').on('click', function () {
  value = value + 1;
});

function render() {
  $('#value').html(value);
}

こんなものが理想ですが、実際に動きません。

それを実現してくれるのがReactです!

先程を同じカウンターをReactで作ってみましょう。
create-react-appと使ってプロジェクトを作ります。
ついでに、ES7 React/Redux/GraphQL/React-Native snippetsという拡張機能もインストールしておきましょう。

npx create-react-app counter-react
...(省略)...
cd counter-react
npm run start

デフォルトのマークアップが入っています。邪魔なので消しましょう。
index.cssApp.cssの中身を空にします。

create-react-appで生成したReactプロジェクトの初歩は、
以下のreturnされるdiv要素内にマークアップやロジック等の処理を書くことになります。

import React from 'react';
import './App.css';

function App() {
  return (
    <div>
      {/* ここに書く */}
    </div>
  );
}

export default App;

ではReact版のカウンターを早速作りましょう。
ReactはコンポーネントというものでUIを管理します。コンポーネント名はCounterを付けておきます。

import React from 'react';
import './App.css';

function App() {
  return (
    <div>
      <Counter />
    </div>
  );
}

export default App;

このままでは<Counter />が存在しないのでコンパイラに怒られます。
そこで<Counter />を定義していきます。

Reactにはpropsstateというパラメータがあります。前者は関数の引数、後者は関数のローカル変数のようなものです。(イメージ)
valueの性質はローカルなものとして、クラスコンポーネントを使ってstateを定義します。
ついでにrenderされるマークアップも用意します。

※Hooksはこの記事ではスルーします

import React from 'react';
import './App.css';

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: 0,
    };
  }

  render() {
    return (
      <div>
        <p>{this.state.value}</p>
        <p>
          <button>Increment</button>
        </p>
      </div>
    );
  }
}

function App() {
  return (
    <div>
      <Counter />
    </div>
  );
}

export default App;

コンポーネントのコーディングが仰々しく面倒に思いますよね?
でも、拡張機能のスニペットを使えば楽々です。
コンストラクタはrconstrenderメソッドはrenと入力してください。

続いてクリック処理に移りましょう。メソッド名はincrementと付けておきます。
ここで注意ですが、クラスに所属するメソッド名なのでthisを忘れないでください。

import React from 'react';
import './App.css';

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: 0,
    };
  }

  render() {
    return (
      <div>
        <p>{this.state.value}</p>
        <p>
          <button onClick={this.increment}>Increment</button>
        </p>
      </div>
    );
  }
}

function App() {
  return (
    <div>
      <Counter />
    </div>
  );
}

export default App;

まだincrementの中身が書いていないのでもう少し準備をします。

  1. クリックイベントで呼び出すメソッドには、this.hoge = this.hoge.bind(this)というおまじないがコンストラクタに必要です。
  2. メソッドをクラス内に記述します。
import React from 'react';
import './App.css';

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: 0,
    };
    this.increment = this.increment.bind(this);
  }

  increment() {}

  render() {
    return (
      <div>
        <p>{this.state.value}</p>
        <p>
          <button onClick={this.increment}>Increment</button>
        </p>
      </div>
    );
  }
}

function App() {
  return (
    <div>
      <Counter />
    </div>
  );
}

export default App;

ようやく準備が整いました。カウントアップできるメソッドを記述しましょう。
this.state.valueを更新しますが、stateの更新にはsetState()メソッドを使います。
Javaでメンバ変数を直接更新せずにsetterを使うようなルールです。

setState()の書き方は用途によって2通りあります。

// 前のstate値を更新に使わない場合:
// 新しい値をセットしたオブジェクトを引数に渡す
this.setState({ hoge: newValue });

// 前のstate値を更新に使う場合: 
// 前のstateを引数に取り、新しい値をセットしたオブジェクトを返す関数を
// 引数に渡す
this.setState((prevState) => ({ hoge: doFuga(prevState) }));

今回は後者になります。

import React from 'react';
import './App.css';

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: 0,
    };
    this.increment = this.increment.bind(this);
  }

  increment() {
    this.setState((prevState) => ({ value: prevState.value + 1 }));
  }

  render() {
    return (
      <div>
        <p>{this.state.value}</p>
        <p>
          <button onClick={this.increment}>Increment</button>
        </p>
      </div>
    );
  }
}

function App() {
  return (
    <div>
      <Counter />
    </div>
  );
}

export default App;

this.setStateってなんだかタイポしそうですね。
でも、sstと入力すれば補完してくれます。

これで無事成功です。

ここで注目すべきは、DOMへの描画部分をわざわざ2回書かなくても良いことです。
値を変える処理の後は反映、また別の処理の後に反映...のような記述をしなくて構いません。
値が変わればDOMも勝手に書き換わってくれます。

素晴らしいと思って頂けましたか?
薄い記事ですが、これを取っ掛かりにReactが普及すれば嬉しく思います。

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

Kubernetes: NodePortを利用したアプリの公開、デプロイ

0.アプリを公開したい

久しぶりに投稿します。今回はKubernetesでNodePort Serviceを利用してアプリを公開する方法を紹介していきます。
Kubernetesを使って試しに、気軽にアプリをデプロイしてみたい(お金はかけたくない。。。)!という方向けです。

今回使用した環境はIBM Cloudですが、どのCloudでも同様にデプロイできると思います。Kubernetes環境の無料枠が一ヶ月で、期限が切れても再び構築することはできます。
無料枠ではIngressなどを使うことはできませんが、Serviceリソースの一つであるNodePortを利用してアプリを公開することはできます。

Dockerコンテナの作成からKubernetes上へのデプロイまでを行なっているので、これらの一連の流れが掴めるようにはなってると思います。

前提

  • IBM Cloud アカウントの取得
  • IBM CloudのKubernetes上にクラスターを構築してあること
  • DockerがインストールされていてDocker Hubのアカウントを持っている
  • 公開してみたいアプリがあること(なんでもよし。今回作成するアプリに関しては以下の環境が必要)
    • Node.js(node: v12.18.2, npm: 6.14.5)環境があること
    • create-react-appコマンドを使えること

1.サンプルアプリのDockerコンテナの作成

今回はcreate-react-appで簡単に作成できるReactアプリをデプロイしてみようと思います。まずはコンテナ化して動作確認します。

1-1. Reactアプリ作成(create-react-appはインストールされている前提)

$ create-react-app my-react-app
$ cd my-react-app

1-2. Dockerfile作成

Dockerfileを以下のように作成し、my-react-appディレクトリ直下に配置します。

Dockerfile
FROM node:12
COPY . /app
WORKDIR /app
RUN npm run build && \
npm install -g serve
CMD [ "serve" , "-s", "build" ]

今回のコンテナ作成の流れとしてはproduction用の静的ファイルを生成し,それを静的ファイルサーバーを用いて実行するものになっています。
静的ファイルサーバー実行時、デフォルトでは5000番ポートを受け付けます。

1-3. ビルドし、ローカルで動くことを確認する

$ docker build -t my-react-app:0.0.1 .

$ docker run -p 5000:5000 my-react-app:0.0.1
INFO: Accepting connections at http://localhost:5000

#localhost:5000でreactアプリが動いていることができたらexit

2.DockerHubにpushする

2-1. 'docker tag'で1で作成したイメージに自分のDocker Hubのアカウント名(レポジトリ名)を付与する

$ docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: <DockerHubアカウント名>
Password:
Login Succeeded

$ docker tag my-react-app:0.0.1 <DockerHubアカウント名>/my-react-app:0.0.1

2-2. イメージをDocker Hubのレポジトリににpushする

my-react-app $ docker push <DockerHubアカウント名>/my-react-app:0.0.1
The push refers to repository [docker.io/bangdr2018/my-react-app]
24531b8429e8: Pushed
ea8d003551da: Pushed
9cee2cb2fb8e: Mounted from library/node
eb3f44bfde1e: Mounted from library/node
3b93aab45097: Mounted from library/node
174e334f3f46: Mounted from library/node
cbe6bbd0c86f: Mounted from library/node
ef5de533cb53: Mounted from library/node
a4c504f73441: Mounted from library/node
e8847c2734e1: Mounted from library/node
b323b70996e4: Mounted from library/node
0.0.1: digest: sha256:f032be9c6a2530de810d1a29b75777a01655e7a23b64a7aa39e81f5154a82640 size: 2638

2-3. イメージがpushできたことDocker Hubのコンソール上で確認(アカウント名は念のため切ってます)

image.png

3. Kubernetesへのデプロイ、アプリの公開

3-1. kubectlコマンドのコンテキストを確認する。

コンテキストが存在しなかったり、ローカルなど異なるコンテキストとなっていた場合は、kubectlコマンドをダウンロードする

// すでにIBM Cloudに構築したKubernetesからkubectlコマンドをダウンロードしていた場合コンテキストは次のようになる
$ kubectl config current-context
<クラスター名>/<クラスターID>

ダウンロードしていなかった場合はIBM Cloudコンソール上でクラスターのプロファイルを開き、「アクセス」の箇所に以下のようにkubectlコマンドのダウンロード方法が載っている(ibmcloudコマンドをすでに使用できる場合「CLIツールの一回かぎりのセットアップ」は不要)。

image.png

3-2. deployment.ymlの作成

以下のようにdeployment.ymlを作成。containerのimageに2でpushしたイメージを指定する

deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-react-app-deployment
spec:
  selector:
    matchLabels:
      app: my-react-app
  template:
    metadata:
      labels:
        app: my-react-app
    spec:
      containers:
      - name: my-react-app
        image: <DockerHubアカウント名>/my-react-app:0.0.1
        resources:
          limits:
            memory: "128Mi"
            cpu: "500m"
        ports:
        - containerPort: 5000

Podが生成、Runnningとなっていることを確認(Podの名前はデプロイメント名に付随する)

$ my-react-app $ kubectl get pods
NAME                                      READY   STATUS    RESTARTS   AGE
my-react-app-deployment-c4f95c7cd-rx8xt   1/1     Running   0          8s

3-3. NodePortを利用したserviceを作成する

以下のようにservice.ymlを作成。selectorのラベル(app: my-react-app)とPodのラベル(app: my-react-app)を一致させる。
ポートの番号は30000-32767の間に指定する。

service.yml
apiVersion: v1
kind: Service
metadata:
  name: my-react-app-service
spec:
  type: NodePort
  selector:
    app: my-react-app
  ports:
  - port: 5000
    targetPort: 5000
    nodePort: 30080
    protocol: "TCP"
    name: "http-port"

serviceが生成されていることを確認の確認(Podの名前はデプロイメント名に付随する)

my-react-app $ kubectl get service
NAME                   TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
my-react-app-service   NodePort    172.21.94.246    <none>        5000:30080/TCP   10s

3-4. Nodeに割り振られているExternal IPを確認する

NodePort Serviceはその名の通り、:<ポート>で受信したトラフィックをコンテナに送信するものなので、nodeのEXTERNAL-IPを確認する。

// -o wideオプションで表示可能
$ kubectl get node -o wide
NAME             STATUS   ROLES    AGE   VERSION        INTERNAL-IP      EXTERNAL-IP(これ!)      OS-IMAGE             KERNEL-VERSION      CONTAINER-RUNTIME
10.144.194.234   Ready    <none>   13d   v1.17.11+IKS   10.144.194.234   159.122.xxx.xxx   Ubuntu 16.04.7 LTS   4.4.0-187-generic   containerd://1.3.4

3-5. 公開されたアプリをみてみる

さあ緊張の瞬間ですが:で公開されたアプリを見てみましょう。

image.png

公開できました!やりましたね!

おわりに

今回はアプリのコンテナ化からKubernetes上へのデプロイまでの一連の流れを紹介してみました。
結構簡単に、かつ柔軟にデプロイできると思いました。

ただKubernetesのメリットとしてはこんなものではないので自分自身も勉強しつつ有益だと思ったらどんどん投稿していこうと思います。

次はKubernetesで構築したアプリの環境変数周りのリソースについて説明してみようかなと思ってます。

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

【React】公式ドキュメントの私的まとめ

公式の私的まとめ

この記事でのコードは公式を参考にしている。

イベント処理

Reactのイベント処理はブラウザのDOMと似ている
違いは以下

  • Reactのイベントは小文字ではなくcamelCase
  • JSXではイベントハンドラとして文字列じゃなくて関数を渡す
HTML
<button onclick="activateLasers()">
  Activate Lasers
</button>
React
<button onClick={activateLasers}>
  Activate Lasers
</button>

このようにReactでは属性名がcamelCaseで、イベントが関数で渡されている

またReactではfalseを返してもデフォルト動作を抑制できない

<a href="#" onclick="console.log('The link was clicked.'); return false">
  Click me
</a>

React では、以下のようになる

function ActionLink() {
  function handleClick(e) {
    e.preventDefault();
    console.log('The link was clicked.');
  }

  return (
    <a href="#" onClick={handleClick}>
      Click me
    </a>
  );
}

e.preventDefault();として抑制している。
eはブラウザと五感を持っている

ReactはDOM生成後にaddEventListenerでイベントを追加する必要はない
代わりに最初にレンダーされるときにリスナを指定する。

JSXのコールバックのthis

javascriptではクラスにメソッドはデフォルトでバインドされない
this.handleClickへのバインドを忘れるとonClickで実際に関数が呼ばれたときに、thisはundefindとなる。

Reactに限らずjavascriptはそういうもの
onClick={this.handleClick}のように()をつけないでメソッドを参照するときそのメソッドはバインドしておく必要がある

とりあえずイベントを使うときはバインドしておけばいいと思う

イベントハンドラに引数を渡す

idという行のIDがあるとき、以下はちゃんと動作する

//bind
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>

ReactイベントeはIDの2番めの引数として渡される。
id以降の追加の引数は自動的に転送される。

意味ワカンネ

条件付きレンダー

以下は公式のログイン状況でどちらかを表示するコンポーネント

function UserGreeting(props) {
  return <h1>Welcome back!</h1>;
}

function GuestGreeting(props) {
  return <h1>Please sign up.</h1>;
}
function Greeting(props) {
  const isLoggedIn = props.isLoggedIn;
  if (isLoggedIn) {
    return <UserGreeting />;
  }
  return <GuestGreeting />;
}
function LoginButton(props) {
  return (
    <button onClick={props.onClick}>
      Login
    </button>
  );
}
function LogoutButton(props) {
  return (
    <button onClick={props.onClick}>
      Logout
    </button>
  );
}
class LoginControl extends React.Component {
  constructor(props) {
    super(props);
    this.handleLoginClick = this.handleLoginClick.bind(this);
    this.handleLogoutClick = this.handleLogoutClick.bind(this);
    this.state = {isLoggedIn: false};
  }

  handleLoginClick() {
    this.setState({isLoggedIn: true});
  }

  handleLogoutClick() {
    this.setState({isLoggedIn: false});
  }

  render() {
    const isLoggedIn = this.state.isLoggedIn;
    let button;
    if (isLoggedIn) {
      button = <LogoutButton onClick={this.handleLogoutClick} />;
    } else {
      button = <LoginButton onClick={this.handleLoginClick} />;
    }

    return (
      <div>
        <Greeting isLoggedIn={isLoggedIn} />
        {button}
      </div>
    );
  }
}

ReactDOM.render(
  <LoginControl />,
  document.getElementById('root')
);

以下の手順で切り替えをしている。

  1. Reactがを実行してLoginControlクラスのコンストラクタを実行する。そこでは2つログイン状況を変更するsetStateを実行する関数がバインドされている。更にstateの初期値を設定する。
  2. Reactはその後render()を実行。ログイン状況を判定してボタン要素を再描画するかを決めている。
  3. render()内でそこでGreetingクラスが呼ばれる。その際に、isLoggedInプロパティ(今のログイン状況の値が入っている)をpropsとして渡している。そこでも判定して表示するReactエレメントを返してボタン要素も描画する。 ##論理 && 演算子による 他の方法で条件付きのレンダーができるが、今は混乱するからif文の方法だけにしておく。

リストとkey

以下はjavascriptでリストを変換する方法

const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map((number) => number * 2);
console.log(doubled);

上記は値を2倍にした配列を生成している。
Reactも同様にリスト変換できる

複数のコンポーネントをレンダリング

const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
  <li>{number}</li>
);

エレメントを配列に格納している

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <li key={number.toString()}>
      {number}
    </li>
  );
  return (
    <ul>{listItems}</ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);

上記は先のコードを同じ出力
<li key={number.toString()}>を書かないと
Warning: Each child in a list should have a unique "key" prop.という警告を受ける
これはkeyを与えとという意味

key

これはReactがどの要素が変更されたかをReactが認識するために使っている

フォーム

通常のフォームを使うとページ遷移が起こるが大半はそうなってほしくない
ここでは制御されたコンポーネントなるテクニックを学ぶらしい

制御されたコンポーネント

HTMLではフォーム要素は自身で状態を保持している
Reactは変更されうる状態はstateに保持される

Reactのstateを信頼できる雄一の情報とすることで、ユーザのフォーム入力で起こることも制御できる。
これを制御されたコンポーネントというらしいがイマイチピンとこない

以下はその例

class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: ''};

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    alert('A name was submitted: ' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <input type="text" value={this.state.value} onChange={this.handleChange} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

ポイント

  • inputのvalueをthis.state.valueとしている
  • onChangeで入力するたびにstateが変わることでフォームを送信する頃には最終入力値が送信される

制御されたコンポーネントでユーザ入力がReactのstateで制御できる

textarea

<textarea value={this.state.value} onChange={this.handleChange} />

Reactではvalue属性を使う

file input

<input type="file" />

これは読み取り専用で制御はできない

複数入力の処理

それぞれのname属性を追加すればevent.target.nameで処理の選択ができる

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

Reactでボタンが押された時にaxiosでAPIコールする方法 with Bootstrap

環境

npm 6.14.8

手順

テストコールするためのプロジェクトを作成

create-react-app test_call_api
cd test_call_api
npm start

を実行すると以下のページにアクセスするとデフォルトのreactのトップ画面が表示されます。

http://localhost:3000

API実行処理を動かすために必要なものをインストール

今回はAPI実行用にaxiosと画面を綺麗にするbootstrapをインストールします。
インストール後はnpm audit fixする。

npm i axios bootstrap react-bootstrap
npm audit fix
vim src/App.js

App.jsの中身を実装

以下の様に実装しました。今回は世界一簡単なAPIの祝日APIから取得いたします。
https://holidays-jp.github.io/

import axios from 'axios';
import React, { Component } from 'react';
import { Container, Row, Col, Button, Table, Form } from 'react-bootstrap';

const API_URL = 'https://holidays-jp.github.io/api/v1/date.json';
/**
APIのレスポンスは以下を想定する
{
  "2017-01-01": "元日",
  "2017-01-02": "元日 振替休日",
  "2017-01-09": "成人の日"
}
*/

export default class App extends Component {
  // 初期値を設定
  constructor(props) {
    super(props);
    this.state = {
      api_data: [],
      // 今回test_paramは使用しないが、パラメータ設定方法の一つとして記載する
      test_param: ''
    };
  }

  /**
   * APIを実行する
   */
  handleTestCallApi() {
    axios
    // パラメータを指定する場合は以下のように設定
    // { params: { test_param: this.state.test_param }}
    .get(API_URL) 
    .then((results) => {
      const data = results.data; // APIレスポンスを取得する
      this.setState({
        api_data: data,
      });
    },
    )
    .catch((error) => {
      if (error.response) {
        // 200系以外の時にエラーが発生する
        console.log(error.response.data);
        console.log(error.response.status);
        console.log(error.response.headers);
      } else if (error.request) {
        console.log(error.request);
      } else {
        // 上記以外のエラーが発生した場合
        console.log('Error', error.message);
      }
    });
  }
  /**
   * 変更があった場合、test_paramを更新する
   * 今回test_paramは使用しないが、パラメータ設定方法の一つとして記載する
   */
  handleChange(event:InputEvent) {
    this.setState({
      test_param: event.target.value,
    });
  }

  render() {
    return (
      <div className="app">
        <Container>
            <h1>API実行する画面</h1>
            <Form>
              <Row>
                <Col className="submit-form">
                  <Form.Group controlId="formBasicShopId">
                    <Form.Control value={this.state.test_param} type="text" name="test_param" onChange={(e) => { this.handleChange(e); }} />
                  </Form.Group>
                </Col>
              </Row>
              <Button onClick={() => this.handleTestCallApi()}>Exec</Button>
            </Form>
            <br />
          <Table>
            <thead  data-type="ok">
              <tr><th>date</th><th>何の日</th></tr>
            </thead>
            <tbody>
              {Object.keys(this.state.api_data).map(key => (
                <tr key={key}>
                  <td>{key}</td><td>{this.state.api_data[key]}</td>
                </tr>
              ))}
            </tbody>
          </Table>
        </Container>
      </div>
    );
  }
}

画面を開いてみます。
http://localhost:3000/

React_App.png

なんか綺麗な画面になっていません、Bootstrapがうまく動いていない様です。

vim public/index.html

index.htmlのmetaタグの下に以下の様にbootstrapを読み込む必要がありました。

    <link
      rel="stylesheet"
      href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
      integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"
      crossorigin="anonymous"
    />

これでアクセスし直します。

React_App.png

うまくいったようです。
Execボタンを押すと祝日情報が表示される様になっています。

React_App.png

おわりに

react.jsでAPIを実行する方法がいまいち調べてもわからなかったのでまとめました。

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

create-react-appでtsyringeを使う方法

「create-react-app」で作ったプロジェクトに「tsyringe」を導入する際に、
「TypeInfo not known for ~」というエラーが出てしまい、解決に苦戦してしまったので備忘録として残します。

create-reacdt-appでプロジェクトを作成

$ npx create-react-app sample --template typescript
$ yarn add tsyringe reflect-metadata
tsconfig.json
{
  "compilerOptions": {
    ~
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  },
  ~
}

cracoでbabelプラグインを追加する

「create-react-app」そのままでは「tsyringe」は使用できないため、「craco」というパッケージを使いました。
これは「Create React App Configuration Override」の略で、babelの構成などを上書きできるパッケージです。

https://github.com/gsoft-inc/craco

yarn add -D babel-plugin-transform-typescript-metadata craco
package.json
"scripts": {
  "start": "craco start",
  "build": "craco build",
  "test": "craco test"
}
craco.config.js
module.exports = function ({ env: _env }) {
  return {
    babel: {
      plugins: ["babel-plugin-transform-typescript-metadata"],
    },
  };
};
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

React appをFirebaseにデプロイ

Reactとは

Reactとは、UIを作成するための、Facebookが開発したJavaScript用ライブラリです。Facebook、Yahoo、Qiita、Wantedlyなども採用しています。
詳細: https://ja.reactjs.org/

Reactのコンセプト

  • Declarative(宣言的である)

  • Component-Based(コンポーネント思考がベースになっている)

  • Learn Once, Write Anywhere(他の分野にも適応できる)

Firebaseとは

Googleが運営するクラウドプラットフォーム。無料枠があり、HerokuのGoogle版。
詳細: https://firebase.google.com/?hl=ja

Firebaseの導入

以下のコマンドをターミナルで実行し、Firebase-CLIをインストール。

$ npm install -g firebase-tools

Googleアカウントを紐づけ

$ firebase login     // 実行後、メールアドレスなどを入力する

Firebaseの初期化

以下を実行してFirebaseを初期化

$ firebase init

初期化後、以下のようにターミナルから、色々聞かれるので

     ######## #### ########  ######## ########     ###     ######  ########
     ##        ##  ##     ## ##       ##     ##  ##   ##  ##       ##
     ######    ##  ########  ######   ########  #########  ######  ######
     ##        ##  ##    ##  ##       ##     ## ##     ##       ## ##
     ##       #### ##     ## ######## ########  ##     ##  ######  ########

❯◯ Database: Deploy Firebase Realtime Database Rules
 ◯ Firestore: Deploy rules and create indexes for Firestore
 ◯ Functions: Configure and deploy Cloud Functions
 ◯ Hosting: Configure and deploy Firebase Hosting sites
 ◯ Storage: Deploy Cloud Storage security rules
 ◯ Emulators: Set up local emulators for Firebase features

◯ Hosting: Configure and deploy Firebase Hosting sites

を選択し、 スペースキー を押した後に Enter

option

次にoptionを聞かれるので

? Please select an option: (Use arrow keys)
❯ Use an existing project 
  Create a new project 
  Add Firebase to an existing Google Cloud Platform project 
  Don't set up a default project 

すでにFirebaseプロジェクトがある場合

Firebase内に、すでにプロジェクトを作成してたら以下を選択し Enter
プロジェクトを選択し Enter

Use an existing project

Firebaseプロジェクトがない場合

初めて作成する時には以下を選択し Enter

Create a new project

次にFirebaseのブラウザからプロジェクトを作成する
プロジェクトの作成は以下参照
https://qiita.com/Watakatsu/items/667f45081a6dfbc11074

プロジェクトとローカルのフォルダを紐づけ

$ firebase use --add

デプロイ

$ firebase deploy

以上

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

【React】ボタンクリックで別のDOM要素のイベントを起動する方法

react-v16

はじめに

ボタンクリックで別のDOM要素のイベントを起動する方法についてです。

Material Uiの<Button />など、あらかじめカスタムされたコンポーネントだと別のDOM要素を紐付けるカスタムは面倒です。
ここではuseRef()を使用し、onClickでDOMの参照に対する操作を行うことで解決します。

※通常は<Form />要素を使用することで複雑な実装なく動作します。

シチュエーション

ボタン(<Button />)と、透明な入力ボックス(<input />)がある
<input type="file" />を使用したファイルアップロードをボタンから行えるようにしたい。

やりたいこと

ボタンをクリックしたら、入力ボックスがクリックされた挙動をさせたい

関数コンポーネント
<Button
  onClick={handleClick}
>

<input
  type="file"
  style={{display: 'none'}}
/>

 

方法

  • React.useRef()を使って、入力ボックス(<input />)の参照を得る
  • onClickしたら、関数内で参照をクリックさせる
関数コンポーネント
const inputRef = React.useRef();

const handleClick = () => inputRef.current.click();

// .....

<Button
  onClick={handleClick}
>

<input
  type="file"
  ref={inputRef}
  style={{display: 'none'}}
/>

まとめ

  • React.useRef()を使うことで、操作したいDOMへの参照を得る
  • onClick内で参照に対する操作を行う

こうすることで、あるボタンから別のDOM要素のイベントを起動できる。

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

create-react-appで作ったwebサイトからサンプルコードを漏れなく消す

React勉強中のある日...

よし、Reactを使って自分のポートフォリオサイトを作ってみるぞー!
create-react-appってコマンドを使えばサクッと環境構築できるっぽいぞ!!
Typescriptは使いたいね〜

% npx create-react-app ham-portfolio --template typescript
Creating a new React app in /Users/ham/ham-portfolio.

...(略)

We suggest that you begin by typing:

  cd ham-portfolio
  yarn start

Happy hacking!
%

よしできた!!
書いてある通りyarn startや〜

スクリーンショット 2020-09-03 0.12.19.png

とりあえず画面は表示できたので環境構築成功!
マジで簡単にできるなー!!
かっこいいポートフォリオを作るぞー!!!

(数日後...)

やっと完成したーーー!!!!
Firebase Hostingとか適当なホスティングサービスで公開したら経歴書代わりにも使えそうやな!!!!!
スクリーンショット 2020-09-03 0.21.32.png

...

ちょっと待って下さい!!!
そのサイト、create-react-appで生成されたサンプルコードが残りまくっていますよー

例えばタブのところに注目です。
reactのアイコンが表示され、タイトルが"React App"になっています。
スクリーンショット_2020-09-03_0_21_32.png

個人で使うだけなら気にしなくても良いですが、公開するのであればサンプルコードのままになっている部分は消しておきたいですね。
この記事ではcreate-react-appで作ったWebアプリで最低限修正すべきところを修正していきます。

ライブラリのバージョン

この記事で使われているライブラリーのバージョンは下記の通り。

% npm --version
6.14.8
% create-react-app --version
3.4.1

修正開始

それではサンプルコードを修正していきます。

public/favicon.ico

Chromeのタブに表示されていたReactのアイコンです。
他にもアドレスバーに表示されたり、ブックマークに表示されたりと意外に露出の多いアイコンです。
適切なアイコンに変更しておきましょう。

通常、ファビコンは16x16ピクセルの GIF、 PNG、または ICO 形式で保存されます。

https://developer.mozilla.org/ja/docs/Glossary/Favicon

public/index.html

title

サイトのタイトルです。
Chromeではタブに表示されています。
Googleの検索結果やSNSでシェアするときにも表示されるので修正しておきましょう。

- <title>React App</title>
+ <title>ham's portfolio</title>

description

サイトの説明です。
こちらもGoogleの検索結果やSNSでシェアするときにも表示されるので修正しおきましょう。

<meta
  name="description"
-  content="Web site created using create-react-app"
+  content="hamのポートフォリオです!!"
/>

lang

日本語サイトであればlang=jaに変更しておきましょう。

- <html lang="en">
+ <html lang="ja">

apple-touch-icon

iPhoneのSafariで"ホーム画面に追加"をした時に表示される画像です。
ついでに変えておきましょう。

- <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
+ <link rel="apple-touch-icon" href="%PUBLIC_URL%/apple-touch-icon.jpg" />

メタタグ追加

サンプルコードを消すという趣旨からはずれますが、作ったWebサイトをFacebookやTwitterなどのSNSでシェアした時に適切な情報が表示されるようにメタタグを追加しておきましょう。

メタタグはogタグを追加します。
詳細は下記を参照してください。
https://developers.facebook.com/docs/sharing/webmasters/?locale=ja_JP

上記にも書いてありますが、シェアデバッガーを使うとタグが正しく設定できているか確認できます。
必ず確認しましょう。

twitter用のタグは下記を参照してください。
https://developer.twitter.com/ja/docs/tweets/optimize-with-cards/guides/getting-started

twitterもCard validatorを使うことでタグが正しく設定できているか確認できます。
こちらも必ず確認しましょう。

今回は下記のように追加してみました。
app_idはFacebook Developerで簡単に発行できます。

public/index.html
<meta property="og:title" content="ham's portfolio" />
<meta property="og:type" content="website" />
<meta property="og:url" content="https://ham-portfolio.web.app/" />
<meta property="og:image" content="https://ham-portfolio.web.app/ham512.jpg" />
<meta property="og:image:alt" content="ham" />
<meta property="og:site_name" content="ham's portfolio" />
<meta property="og:description" content="hamのポートフォリオです!!" />
<meta property="fb:app_id" content="1975794755877620" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@hamchance0215" />
<meta name="twitter:creator" content="@hamchance0215" />
<meta name="twitter:title" content="ham's portfolio" />
<meta name="twitter:description" content="hamのポートフォリオです!!" />
<meta name="twitter:image" content="https://ham-portfolio.web.app/ham512.jpg" />
<meta name="twitter:image:alt" content="ham" />

コメントを消す

HTML内に様々な説明コメントが入っています。
ビルドするとコメントは削除されるのでHTMLソースを見た時に表示されるわけではないですが、Githubなどでコードを公開するのであれば消しておきましょう。

ソースを第三者が見た時に、下記のような初期構築時の説明コメントが残っているとチュートリアルとかをサクッとやっただけだなーと思われることがあります。

- <!--
-   This HTML file is a template.
-   If you open it directly in the browser, you will see an empty page.
-
-   You can add webfonts, meta tags, or analytics to this file.
-   The build step will place the bundled scripts into the <body> tag.
-
-   To begin the development, run `npm start` or `yarn start`.
-   To create a production bundle, use `npm run build` or `yarn build`.
- -->

Service Worker

create-react-appで作成するとService Workerのコードが入っています。
Service Workerを有効にすると、Webサイトをアプリのように振る舞うようにすることができます。
私は初めて見たときは得体のしれないものでめんどくさそうだと思い無視してしまいましたが簡単に有効にできるのでやってみましょう!

Service Workerについては下記を参照
https://developers.google.com/web/fundamentals/primers/service-workers?hl=ja

src/index.tsx

コメントに書かれている通り、unregister()register()に修正すればService Workerが有効になります。

src/index.tsx
  // If you want your app to work offline and load faster, you can change
  // unregister() to register() below. Note this comes with some pitfalls.
  // Learn more about service workers: https://bit.ly/CRA-PWA
- serviceWorker.register();
+ serviceWorker.register();

manifest.json

Service Workerを有効にしてPWAとして動作させるためにmanifest.jsonで名称やアイコンなど各種情報を設定する必要があります。

マニフェストファイルについては下記参照
https://developer.mozilla.org/ja/docs/Web/Manifest

今回は下記のように修正してみました。

public/manifest.json
{
  "short_name": "ham's p",
  "name": "ham's portfolio",
  "icons": [
    {
      "src": "favicon.ico",
      "sizes": "48x48",
      "type": "image/x-icon"
    },
    {
      "src": "ham144.png",
      "type": "image/png",
      "sizes": "144x144"
    },
    {
      "src": "ham192.jpg",
      "type": "image/jpeg",
      "sizes": "192x192"
    },
    {
      "src": "ham512.jpg",
      "type": "image/jpeg",
      "sizes": "512x512"
    }
  ],
  "start_url": "/",
  "Scope": "/",
  "display": "standalone",
  "theme_color": "#000000",
  "background_color": "#ffffff"
}

正しく設定されているかは、Chrome Dev ToolsのApplicationタブ、 Application > Manifestで確認することが出来ます。
情報に間違いがある場合は警告が表示されるので、警告がなくなるように修正しましょう。

スクリーンショット 2020-09-10 23.31.21.png

README.md

サイトを公開するだけであれば必要ありませんが、GitHubも公開するのであればREADMEも修正しておくと良いでしょう。
デフォルトではcreate-react-appやReact自体の説明や使えるscriptの説明が記載されています。
作ったサイトの説明や公開しているURLを追記すると良いと思います。

修正後の確認

下記のようになりました。
スクリーンショット 2020-09-11 0.05.55.png

ソースを覗かれても大丈夫!!
スクリーンショット 2020-09-11 0.07.31.png

シェアしても大丈夫!!
スクリーンショット 2020-09-11 0.08.21.png

ググっても大丈夫!!
※このQiita用に作ったページはクローリングされなかったのでイメージはサンプルです・・・
きちんと内容のあるサイトを作るとGoogleもクローリングしてくれます!
サイトを作ったらGoogle Search Consoleで確認してみましょう。
https://support.google.com/webmasters#topic=9128571

スクリーンショット 2020-09-13 23.43.19.png

Githubを見られても大丈夫!!
スクリーンショット 2020-09-11 0.35.48.png

Service Workderを有効にしてマニフェストファイルもきちんと設定しているのでブラウザアプリとして追加することも出来ます!!

  • Mac Chrome
    スクリーンショット 2020-09-11 0.14.13.png

  • Android Chrome
    Screenshot_20200911-001238_Chrome.jpg

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

react-diff-viewer を使って GitHub 風の diff を表示する

react-diff-viewer は React アプリケーションで GitHub 風の Diff を簡単に表示することできるライブラリです。

公式のデモはこちらです。

React.js で Diff を表示するライブラリは他にも、react-diff-view などがありますが、こちらは react-diff-viewer に関する記事になりますのでお間違いなきように。

サンプルコード

react-diff-viewer-sample

環境情報

  • yarn: 1.22.4
  • react: 16.13.1
  • react-diff-viewer: 3.1.1

使い方

インストール

$ yarn add react-diff-viewer

# or

$ npm i react-diff-viewer

サンプル実装

App.jsx
import React, { PureComponent } from "react";
import ReactDiffViewer from "react-diff-viewer";

const oldCode = `
const a = 10
const b = 10
const c = () => console.log('foo')
if(a > 10) {
  console.log('bar')
}
console.log('done')
`;
const newCode = `
const a = 10
const boo = 10
if(a === 10) {
  console.log('bar')
}
`;

class Diff extends PureComponent {
  render = () => {
    return (
      <ReactDiffViewer
        oldValue={oldCode}
        newValue={newCode}
        splitView={true}
        leftTitle={"oldCode"}
        rightTitle={"newCode"}
      />
    );
  };
}

export default Diff;

表示される画面

image.png

オプション

下記のサンプルコードを使用して、いくつかのオプションを紹介します。

App2.jsx
import React, { PureComponent } from "react";
import ReactDiffViewer from "react-diff-viewer";

const oldText = `
# react-diff-viewer を使って GitHub 風の diff を表示する

[react-diff-viewer](https://github.com/praneshr/react-diff-viewer) は React アプリケーションで GitHub 風の Diff を簡単に表示することできるライブラリです。


React.js で Diff を表示するライブラリは他にも、[react-diff-view](https://github.com/otakustay/react-diff-view) がありますが、こちらは react-diff-viewer に関する記事になりますのでお間違いなきように。

## SampleCode

[react-diff-viewer-sample](https://github.com/t0yohei/react-diff-viewer-sample)
`;
const newText = `
# react-diff-viewer を使って GitHub 風の diff を表示する

[react-diff-viewer](https://github.com/praneshr/react-diff-viewer) は React アプリケーションで GitHub 風の Diff を簡単に表示することできるライブラリです。

[公式のデモはこちら](https://praneshravi.in/react-diff-viewer/)です。

React.js で Diff を表示するライブラリは他にも、[react-diff-view](https://github.com/otakustay/react-diff-view) がありますが、こちらは react-diff-viewer に関する記事になりますのでお間違いなきように。

## サンプルコード

[react-diff-viewer-sample](https://github.com/t0yohei/react-diff-viewer-sample)

## 環境情報

- yarn: 1.22.4
- react: 16.13.1
- react-diff-viewer: 3.1.1
`;

class Diff extends PureComponent {
  render = () => {
    return (
      <ReactDiffViewer
        oldValue={oldText}
        newValue={newText}
        splitView={false}
        disableWordDiff={true}
        hideLineNumbers={true}
        useDarkTheme={true}
      />
    );
  };
}

export default Diff;

表示される画面

image.png

オプションの説明

Prop 初期値 詳細
splitView boolean true unifiedsplit の表示を切り替えます。
disableWordDiff boolean false diff の中の単語 diff の表示・非表示を切り替えます。
hideLineNumbers boolean false 行番号の表示・非表示を切り替えます。
useDarkTheme boolean true ダークモードの ON/OFF を切り替えます

その他、詳細なオプションは下記をご参照ください。
https://github.com/praneshr/react-diff-viewer#props

実装上の注意

UIkit v3.5.7 などをアプリケーション全体に適用している場合、 ReactDiffViewer コンポーネント内の pre タグのスタイルが UIkit などにより上書かれてしまい、 react-diff-viewer のスタイルが崩れる場合があります。
dirty hacking な回避方法としては、下記のような css ファイルを別途用意して、 react-diff-viewer を使用している jsx のファイル内で require してあげるなどがあります。

style.scss
pre {
  padding: 0px !important;
  border: none !important;
  border-radius: unset !important;
  background: inherit !important;
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【React.js】class構文 と fanction構文

react-article-img.png

前書き

Reactを学習していた中で "class構文・fanction構文" を学習しましたので、こちらでアウトプットとして記録いたします。
学習されている方にお役に立てると非常に嬉しいです。

また、コードは Github で公開しているので気になるかたはダウンロードしてみてください。

class構文 と function構文とは

Reactをコーディングする方法として "class構文""fanction構文" があります。
これらの表記は↓になります。

Class構文
import React from 'react';

class 関数名 extends React.Component {
    render(){
        return(
         <React.Fragment>
          処理
         </React.Fragment>
        );
    }
}

export default 関数名;
function構文
import React from 'react';

function 関数名(引数) {
  return (
    <div className="Comment">
     処理
    </div>
  );
}

export default 関数名;

また、function構文にはもう1つ表記方法があります。

arrow関数
import React from 'react';

const 関数名 = (引数) => {

    return(
        <>
        処理
        </>
    )
}

export default 関数名;

こちらは、ES2015(ES6)アロー関数で表記されたものです。

どの構文で書けばいいのか?

業務環境により、構文使用の優先度は異なると思いますが、できるだけなら "function構文のアロー関数" で表記する方が良いです。

その理由は "class構文" よりも "function構文" の方が シンプル に表現できるため。
コーディングをする上では、複雑なコードを書くよりも、シンプルに表記される方が好ましいです。
また、Javascriptの使用は現在では "ES2015(ES6)" が推奨されます。アロー関数は ES2015 に該当するので使っていく方が良いでしょう。

しかし、アロー関数 は全てのブラウザで表示可能な訳ではありません。
現在では大抵のブラウザは対応しますが、古い環境下だと対応していないのでこれは知識に入れましょう。

(アロー関数の動作環境)
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/Arrow_functions

また、次からは MAP配列を使った "class構文" と "function構文" のページを比較します。

class構文で書く

react-img-1.png

ここでは、横並びのコンテンツを "class構文" で書いてみます。
次に、function構文で同じ者を作るので、比較をしてみましょう

Class構文(Language.js)
import React from 'react';

class Language extends React.Component {
    // Übergeben "props" mit Daten als Argument
    render(){
        return(
            <div className='language-item'>
                <div className="language-name">{this.props.name}</div>
                <img
                className='language-image'
                src={this.props.image}
                />
                <div className="language-introduction">{this.props.introduction}</div>
                </div>
        );
    }
}



export default Language;

(行っていること)
データを持つpropsを引数に渡しています。
class構文だとこの処理に "this.props.image" など this を使うのが特徴的です。

Class構文(Language.js)
import React from 'react';
import Language from './Language'
import './App.css';

class Main extends React.Component{
  render(){
    //Datenarray Definition (MAP)
    const languageList = [
      {
        name: 'English',
      image: 'http://hudehisa.sakura.ne.jp/gitgub_image/react_flag_england.png',
      introduction: 'Diese Sprache wird vom Vereinigten Königreich und den Vereinigten Staaten gesprochen.'
      },
      {
        name: 'Japanish',
      image: 'http://hudehisa.sakura.ne.jp/gitgub_image/react_flag_japan.png',
      introduction: 'Diese Sprache wird in Japan gesprochen.'
      },
      {
        name: 'Deutsch',
      image: 'http://hudehisa.sakura.ne.jp/gitgub_image/react_flag_germany.png',
      introduction: 'Diese Sprache wird in Deutschland und der Schweiz gesprochen.'
      }
    ];

    return(
      <div>
        <h1>Welche Sprache sprichst du?</h1>
        <div className='language'>
          {/* Datenarray aufrufen */}
          {languageList.map((languageItem)=> {
            return(
              <Language
              name = {languageItem.name}
              image = {languageItem.image}
              introduction = {languageItem.introduction}
              />
            )
          })}
        </div>
        </div>
    );
  }
}

export default Main;

(行っていること)
MAP配列を定義し、(MAPの)データ配列を呼び出しています。
アロー関数を使って (languageItem) => {return ‥} の中です。

Class構文(index.js)
import React from 'react';
import ReactDOM from 'react-dom';
import './App.css';
import Header from './Header';
import Footer from './Footer';
import Main from './Main';
import * as serviceWorker from './serviceWorker';

ReactDOM.render(
  <React.StrictMode>
   <Header />
   <Main />
   <Footer />
  </React.StrictMode>,
  document.getElementById('root')
);

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

(行っていること)
個別のコンポネートを index.js に記しています。

※こちらでは、cssや他コンポネートは記していません。下記のgithubでコーディングファイルを共有しているので、気になった方はダウンロードをして確認してみてください。

Github
こちらでは、class構文のファイルをダウンロードできます。
(Githubでは、CSS・HTMLなど他データも含まれます)

class構文では "this" や が特徴的です。

では、function構文(アロー関数)で書いてみます。

function構文(アロー関数)で書く

Function構文(Main.js)
import React from 'react';
import Language from './Language'
import './App.css';

const Main = (props) => {
  //Datenarray Definition (MAP)
  let languageList = [
    {
      name: 'English',
    image: 'http://hudehisa.sakura.ne.jp/gitgub_image/react_flag_england.png',
    introduction: 'Diese Sprache wird vom Vereinigten Königreich und den Vereinigten Staaten gesprochen.'
    },
    {
      name: 'Japanish',
    image: 'http://hudehisa.sakura.ne.jp/gitgub_image/react_flag_japan.png',
    introduction: 'Diese Sprache wird in Japan gesprochen.'
    },
    {
      name: 'Deutsch',
    image: 'http://hudehisa.sakura.ne.jp/gitgub_image/react_flag_germany.png',
    introduction: 'Diese Sprache wird in Deutschland und der Schweiz gesprochen.'
    }
  ];

  return(
    <>
     <h1>Welche Sprache sprichst du?</h1>
        <div className='language'>
          {/* Datenarray aufrufen */}
          {languageList.map((languageItem)=> {
            return(
              <Language
              name = {languageItem.name}
              image = {languageItem.image}
              introduction = {languageItem.introduction}
              />
            )
          })}
        </div>
    </>
  )
}

export default Main;

(行っていること)
MAP配列を定義し、(MAPの)データ配列を呼び出しています。
アロー関数を使って (languageItem) => {return ‥} の中です。

Function構文(Language.js)
import React from 'react';

const Language = (props) => {
// Übergeben "props" mit Daten als Argument
    return(
        <div className='language-item'>
        <div className="language-name">{props.name}</div>
        <img
        className='language-image'
        src={props.image}
        />
        <div className="language-introduction">{props.introduction}</div>
        </div>
    )
}

export default Language;

(行っていること)
データを持つpropsを引数に渡しています。
function構文だと this がないのが特徴的です。

Github
こちらでは、アロー関数とアロー関数ではないのファイルをダウンロードできます。
(Githubでは、CSS・HTMLなど他データも含まれます)

以上が Class構文 と function構文 でした。
また下記は、function構文の注意点です。

function構文の注意! "state" が使えない

Reactでの制作経験があると、多くの場合は "state" 処理をしています。
しかし、タイトルにある様に "function構文" では state が使えません。なので、どうしても state を使いたい場合は "class構文" が書く必要があります。

しかし、先に述べた様に "function構文" を推奨しています。
では、 functionでstateを使用したい場合はどうすればいいのだろうか?
解決方法があります。それは "React hocks" を使用することです。

あとがき

ここまで読んでいただき、ありがとうございました。
学習をしていて、class構文やfunction構文で悩んでいたので、こちらを学習しました。
まだまだ、Reactについては浅学ですが、学習を続けたいと思います。

参考リンク

日本一わかりやすいReact入門#4 コンポーネント間でデータの受け渡しと再利用をしよう

Myリンク

また、Twitter・Portfolio のリンクがありますので、気になった方は
ぜひ繋がってください。プログラミング学習を共有できるフレンドが出来るととても嬉しいです。

Twitter
Portfolio
Github

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

【React.js】class構文 と function構文

react-article-img.png

前書き

Reactを学習していた中で "class構文・function構文" を学習しましたので、こちらでアウトプットとして記録いたします。
学習されている方にお役に立てると非常に嬉しいです。

また、コードは Github で公開しているので気になるかたはダウンロードしてみてください。

class構文 と function構文とは

Reactをコーディングする方法として "class構文""fanction構文" があります。
これらの表記は↓になります。

Class構文
import React from 'react';

class 関数名 extends React.Component {
    render(){
        return(
         <React.Fragment>
          処理
         </React.Fragment>
        );
    }
}

export default 関数名;
function構文
import React from 'react';

function 関数名(引数) {
  return (
    <div className="Comment">
     処理
    </div>
  );
}

export default 関数名;

また、function構文にはもう1つ表記方法があります。

arrow関数
import React from 'react';

const 関数名 = (引数) => {

    return(
        <>
        処理
        </>
    )
}

export default 関数名;

こちらは、ES2015(ES6)アロー関数で表記されたものです。

どの構文で書けばいいのか?

業務環境により、構文使用の優先度は異なると思いますが、できるだけなら "function構文のアロー関数" で表記する方が良いです。

その理由は "class構文" よりも "function構文" の方が シンプル に表現できるため。
コーディングをする上では、複雑なコードを書くよりも、シンプルに表記される方が好ましいです。
また、Javascriptの使用は現在では "ES2015(ES6)" が推奨されます。アロー関数は ES2015 に該当するので使っていく方が良いでしょう。

しかし、アロー関数 は全てのブラウザで表示可能な訳ではありません。
現在では大抵のブラウザは対応しますが、古い環境下だと対応していないのでこれは知識に入れましょう。

(アロー関数の動作環境)
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/Arrow_functions

また、次からは MAP配列を使った "class構文" と "function構文" のページを比較します。

class構文で書く

react-img-1.png

ここでは、横並びのコンテンツを "class構文" で書いてみます。
次に、function構文で同じ者を作るので、比較をしてみましょう

Class構文(Language.js)
import React from 'react';

class Language extends React.Component {
    // Übergeben "props" mit Daten als Argument
    render(){
        return(
            <div className='language-item'>
                <div className="language-name">{this.props.name}</div>
                <img
                className='language-image'
                src={this.props.image}
                />
                <div className="language-introduction">{this.props.introduction}</div>
                </div>
        );
    }
}



export default Language;

(行っていること)
データを持つpropsを引数に渡しています。
class構文だとこの処理に "this.props.image" など this を使うのが特徴的です。

Class構文(Language.js)
import React from 'react';
import Language from './Language'
import './App.css';

class Main extends React.Component{
  render(){
    //Datenarray Definition (MAP)
    const languageList = [
      {
        name: 'English',
      image: 'http://hudehisa.sakura.ne.jp/gitgub_image/react_flag_england.png',
      introduction: 'Diese Sprache wird vom Vereinigten Königreich und den Vereinigten Staaten gesprochen.'
      },
      {
        name: 'Japanish',
      image: 'http://hudehisa.sakura.ne.jp/gitgub_image/react_flag_japan.png',
      introduction: 'Diese Sprache wird in Japan gesprochen.'
      },
      {
        name: 'Deutsch',
      image: 'http://hudehisa.sakura.ne.jp/gitgub_image/react_flag_germany.png',
      introduction: 'Diese Sprache wird in Deutschland und der Schweiz gesprochen.'
      }
    ];

    return(
      <div>
        <h1>Welche Sprache sprichst du?</h1>
        <div className='language'>
          {/* Datenarray aufrufen */}
          {languageList.map((languageItem)=> {
            return(
              <Language
              name = {languageItem.name}
              image = {languageItem.image}
              introduction = {languageItem.introduction}
              />
            )
          })}
        </div>
        </div>
    );
  }
}

export default Main;

(行っていること)
MAP配列を定義し、(MAPの)データ配列を呼び出しています。
アロー関数を使って (languageItem) => {return ‥} の中です。

Class構文(index.js)
import React from 'react';
import ReactDOM from 'react-dom';
import './App.css';
import Header from './Header';
import Footer from './Footer';
import Main from './Main';
import * as serviceWorker from './serviceWorker';

ReactDOM.render(
  <React.StrictMode>
   <Header />
   <Main />
   <Footer />
  </React.StrictMode>,
  document.getElementById('root')
);

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

(行っていること)
個別のコンポネートを index.js に記しています。

※こちらでは、cssや他コンポネートは記していません。下記のgithubでコーディングファイルを共有しているので、気になった方はダウンロードをして確認してみてください。

Github
こちらでは、class構文のファイルをダウンロードできます。
(Githubでは、CSS・HTMLなど他データも含まれます)

class構文では "this" や が特徴的です。

では、function構文(アロー関数)で書いてみます。

function構文(アロー関数)で書く

Function構文(Main.js)
import React from 'react';
import Language from './Language'
import './App.css';

const Main = (props) => {
  //Datenarray Definition (MAP)
  let languageList = [
    {
      name: 'English',
    image: 'http://hudehisa.sakura.ne.jp/gitgub_image/react_flag_england.png',
    introduction: 'Diese Sprache wird vom Vereinigten Königreich und den Vereinigten Staaten gesprochen.'
    },
    {
      name: 'Japanish',
    image: 'http://hudehisa.sakura.ne.jp/gitgub_image/react_flag_japan.png',
    introduction: 'Diese Sprache wird in Japan gesprochen.'
    },
    {
      name: 'Deutsch',
    image: 'http://hudehisa.sakura.ne.jp/gitgub_image/react_flag_germany.png',
    introduction: 'Diese Sprache wird in Deutschland und der Schweiz gesprochen.'
    }
  ];

  return(
    <>
     <h1>Welche Sprache sprichst du?</h1>
        <div className='language'>
          {/* Datenarray aufrufen */}
          {languageList.map((languageItem)=> {
            return(
              <Language
              name = {languageItem.name}
              image = {languageItem.image}
              introduction = {languageItem.introduction}
              />
            )
          })}
        </div>
    </>
  )
}

export default Main;

(行っていること)
MAP配列を定義し、(MAPの)データ配列を呼び出しています。
アロー関数を使って (languageItem) => {return ‥} の中です。

Function構文(Language.js)
import React from 'react';

const Language = (props) => {
// Übergeben "props" mit Daten als Argument
    return(
        <div className='language-item'>
        <div className="language-name">{props.name}</div>
        <img
        className='language-image'
        src={props.image}
        />
        <div className="language-introduction">{props.introduction}</div>
        </div>
    )
}

export default Language;

(行っていること)
データを持つpropsを引数に渡しています。
function構文だと this がないのが特徴的です。

Github
こちらでは、アロー関数とアロー関数ではないのファイルをダウンロードできます。
(Githubでは、CSS・HTMLなど他データも含まれます)

以上が Class構文 と function構文 でした。
また下記は、function構文の注意点です。

function構文の注意! "state" が使えない

Reactでの制作経験があると、多くの場合は "state" 処理をしています。
しかし、タイトルにある様に "function構文" では state が使えません。なので、どうしても state を使いたい場合は "class構文" が書く必要があります。

しかし、先に述べた様に "function構文" を推奨しています。
では、 functionでstateを使用したい場合はどうすればいいのだろうか?
解決方法があります。それは "React hocks" を使用することです。

あとがき

ここまで読んでいただき、ありがとうございました。
学習をしていて、class構文やfunction構文で悩んでいたので、こちらを学習しました。
まだまだ、Reactについては浅学ですが、学習を続けたいと思います。

参考リンク

日本一わかりやすいReact入門#4 コンポーネント間でデータの受け渡しと再利用をしよう

Myリンク

また、Twitter・Portfolio のリンクがありますので、気になった方は
ぜひ繋がってください。プログラミング学習を共有できるフレンドが出来るととても嬉しいです。

Twitter
Portfolio
Github

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