20200103のReactに関する記事は5件です。

GitHub Pages でReact Appを公開

はじめに

create-react-appで作成したアプリをGitHub Pagesで公開してみます。

リポジトリの作成

$ yarn create react-app myapp --template typescript
$ cd myapp
$ git commit -m "first commit"
$ git remote add origin git@github.com:pure-adachi/myapp.git
$ git push -u origin master

gh-pagesでデプロイ

gh-pagesインストール

$ yarn add gh-pages
package.json
  // ...
  "homepage": "http://pure-adachi.github.io/myapp",
  "scripts": {
    // ...
    "deploy": "yarn build && gh-pages -d build"
  },

デプロイ

$ yarn deploy

何度かパスワードを聞かれました。

コミット&プッシュせずに、更にはmasterブランチですがデプロイ出来ました。

自動でgh-pagesブランチが作成されて、GitHub Pagesのブランチ設定も行われます。

-bオプションでブランチの指定が出来ますが、Github Pagesで配信可能なブランチはmastergh-pagesなので
デフォルトのgh-pagesブランチを使うことにしました。

スクリーンショット 2020-01-03 22.34.05.png

http://pure-adachi.github.io/myapp にアクセスすると動作が確認出来ました。

スクリーンショット 2020-01-03 22.34.49.png

終わりに

簡単に出来ましたね

参考文献

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

Firebase+React+Reduxで多機能チャットを実装しよう【リアルタイムチャット~React編~】

Firebase&React&Reduxで多機能チャットを実装しよう【リアルタイムチャット編】

今回から本格的にReactとReduxを触っていきます。
一気に難易度が上がるので覚悟してください!笑

ガイド

ディレクトリ構成

前回までのおさらい。
ディレクトリ構成は現在以下の通りです。

要らないファイルを削除して、ディレクトリを追加作成します。

Before
react-chat
 │- build/
 │- public/
 │   │- favicon.ico
 │   │- index.html
 │   │- logo192.png <-- REM
 │   │- logo512.png <-- REM
 │   │- manifest.json
 │   └  robots.txt
 │- src/
 │   │- firebase/
 │   │   │- config.js
 │   │   └  index.js
 │   └  index.js
 │- node_modules/
 │- .firebaserc
 │- database.rules.json
 │- firebase.json
 │- package.json
 │- package-lock.json
 └  storage.rules.json
After
react-chat
 │- build/
 │- public/
 │   │- favicon.ico
 │   │- index.html
 │   │- manifest.json
 │   └  robots.txt
 │- src/
 │   │- components/ <-- ADD
 │   │- containers/ <-- ADD
 │   │- firebase/
 │   │   │- config.js
 │   │   └  index.js
 │   │- templates/ <-- ADD
 │   │- index.js 
 │   └  style.css <-- ADD
 │- node_modules/
 │- .firebaserc
 │- database.rules.json
 │- firebase.json
 │- package.json
 │- package-lock.json
 └  storage.rules.json

React基本ファイルの準備

create-react-appで作成した開発環境の基本を簡単に説明しておきます。

  • public:雛形となるhtmlファイルを格納するディレクトリ
  • src:コンパイル前のソースコードを格納するディレクトリ
  • npm run buildsrc配下のファイルをコンパイルするコマンド
  • build:コンパイルされたファイルを格納するディレクトリ

雛形となるHTMLファイル

雛形となるHTMLファイルには以下を記載します。

  • サイトのタイトルやメタ情報
  • Firebaseに必要なスクリプト
  • Reactコンポーネントをrenderするルートdiv
public/index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Firebase React Chat!</title>
    <!-- update the version number as needed -->
    <script defer src="/__/firebase/7.5.1/firebase-app.js"></script>
    <!-- include only the Firebase features as you need -->
    <script defer src="/__/firebase/7.5.1/firebase-auth.js"></script>
    <script defer src="/__/firebase/7.5.1/firebase-database.js"></script>
    <script defer src="/__/firebase/7.5.1/firebase-messaging.js"></script>
    <script defer src="/__/firebase/7.5.1/firebase-storage.js"></script>
    <!-- initialize the SDK after all desired features are loaded -->
    <script defer src="/__/firebase/init.js"></script>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

Reactコンポーネントをindex.jsファイル

npm run buildでコンパイルする際に参照されるjsファイルです。
細かい説明は省きますが、後ほど登場するファイルたちの情報をまとめておきます。

src/index.js
import React from 'react';
import * as ReactDOM from 'react-dom';
import {Provider} from 'react-redux';
import {RootContainer} from './containers';
import {configureStore} from './modules';
import './style.css'

ReactDOM.render(
    <Provider store={configureStore()}>
        <RootContainer />
    </Provider>,
    document.getElementById('root')
);

ReactDOM.render(element, container)で、Reactコンポーネント(element)を雛形HTMLのDOM(container)にレンダーして表示させています。

先ほど作成したHTMLファイル内の、idがrootのdiv要素にレンダーさせているということですね。

それでは、レンダーされるコンポーネントを作っていきましょう。

Reactコンポーネントの作成

ReactをReduxと共に用いる場合、コンポーネントは2つに分けるのが一般的です。

  1. Presentational Components --> 見た目(View)を担当する。「コンポーネント」と呼ばれる
  2. Container Components --> ロジック(振る舞い)に関わる。「コンテナー」と呼ばれる。

より詳細な定義はコチラの記事を参考にしてください。

上記を踏まえて、ディレクトリ構成で追加したディレクトリに格納するファイルの役割は以下の通りです。

  • components: 最小構成要素(パーツ)となるPresentational Components、子コンポーネントです。
  • templates: components内のパーツを組み合わせたPresentational Components、親コンポーネントです。
  • containers: templatesPresentational Componentsと"状態"を紐づけるための中継役、Container Componentsです。

ログインページを例にすると
componentsは「ボタン」や「テキストボックス」
templatesは「ボタン」や「テキストボックス」を組み合わせた「ログインフォーム」
containersはログイン処理後の見た目(View)がどのように変化するのか定義

少し難しいですよね。

「コンポーネントは見た目(View)のみを持ち、状態(State)と分離させる」というReduxの設計思想を実現するための構成だと思ってください。

それでは、実際にリアルタイムチャットを実装するためのファイルを書いていきます。

componentsファイルの作成

チャットを実装するためには以下のパーツが必要だと考えました。

  1. メッセージ表示エリア
  2. メッセージ入力エリア
  3. メッセージ送信ボタン

この記事では2と3について解説します。

当記事ではMaterial-UIを使っていますが、詳しい解説を割愛します。
デザインのカスタマイズには癖があるけど、それっぽいUIが簡単に作れて便利だゾ。

また、デモページを作った都合上、独自CSSを使っています。
CSSはGithubのソースコードから確認してください。(src/style.css)に記述しています。

src/components/Chat/TextInput.js
import React from 'react';
import TextField from '@material-ui/core/TextField';

const TextInput = (props) => {
    return (
        <form className="p-chat__textarea c-grid-center" noValidate autoComplete="off">
            <TextField
                id="standard-text"
                className="c-grid-full"
                margin="normal"
                label="メッセージを入力..."
                multiline
                rowsMax="4"
                onChange={e => props.onChange(e.target.value)}
                value={props.value}
            />
        </form>
    );
};

export default TextInput;
src/components/Chat/SendButton.js
import React from 'react';
import Button from '@material-ui/core/Button';
import SendIcon from '@material-ui/icons/Send';

const SendButton = (props) => {
    return (
        <Button
            variant="contained"
            color="primary"
            className="p-chat__button-send"
            onClick={() => props.onClick(props.value, props.roomId, props.fromId, props.toId, props.userIds)}>
          <SendIcon />
        </Button>
    );
}

export default SendButton;

それぞれのポイントを解説します。

両コンポーネントは、Stateless Functional Componentsという形式で宣言されています。

初期のReactでは、Classを用いてコンポーネントを宣言していました。
近年のReactでは、Stateless Functional Components、つまり"関数"として宣言することが推奨されています。

Stateless Functional Componentsには以下のメリットがあります。

  • constructorを使わなくて良い
  • thisが必要ない
  • 状態を持たない(stateless)コンポーネントにできる

つまり、コードがシンプルになってハッピーってことですね☆

また、ES6のアロー関数を使ってさらにシンプルに書いています。

そして重要なのが、関数の引数に渡しているpropsです。
この部分const TextInput = (props) => {です。
この部分const SendButton = (props) => {ですよ。

propsは親コンポーネントから渡された引数を一挙に受け取ります。
親コンポーネントからvalueとして渡した引数を、子コンポーネントでprops.valueのように参照することができます。

props.onClickprops.onChangeは、状態を変更するためのActionsを呼び出します。
Actionsについては[次の記事]で解説します。

templatesファイルの作成

templatesディレクトリ配下にChat.jsを作成します。
Chat.jsは親コンポーネントとして、先ほど作成したコンポーネントをまとめます。

ファイルが長いので部分ごとに解説します。

import

ファイル冒頭のimport文です。

src/templates/Chat.js
import React, {Component} from 'react';
import {Chat, Common} from '../components';
import {database} from '../firebase/index'

components/index.jsexportした"Chat"と"Common"のコンポーネントをimportします。

constructorとrender

src/templates/Chat.js
class ChatTemplate extends Component {
    constructor(props) {
        super(props);
    }

    /* 中略 */

    render() {
        return (
             <div className="p-chat">
                <Common.NavBar
                    value={this.props.messages}
                    actions={this.props.actions.messages}
                    back={this.props.actions.messages.backToRooms}
                    configure={this.props.actions.messages.configure}
                    signOut={this.props.actions.messages.signOut}
                />
                <div className="p-chat__area" id="scroll-area">
                    {this.props.messages.msgs.map((m, i) => (
                        <Chat.AlignItemsList key={i} msgs={m} />
                    ))}
                </div>
                <div className="c-grid__row">
                    <Chat.TextInput
                        onChange={this.props.actions.messages.change}
                        value={this.props.messages.value}
                    />
                    <Chat.SendButton
                        onClick={this.props.actions.messages.submit}
                        value={this.props.messages.value}
                        roomId={this.props.messages.roomId}
                        fromId={this.props.messages.userId}
                        toId={this.props.messages.partnerId}
                        userIds={this.props.messages.userIds}
                    />
                </div>
            </div>
        );
    }
}

export default ChatTemplate

親コンポーネントではcomponentDidMount()などのライフサイクルを使いたいので、Stateless Functional ComponentsではなくClass Componentsで宣言します。

constructorの宣言をします。
this.propsでreduxのStoreに保存されているGlobal Stateを参照できます。
(ごめんなさい、Storeについても[次の記事]で解説します...!)

src/templates/Chat.js
constructor(props) {
    super(props);
}

続いて、render部分です。
return()のなかにDOMやコンポーネントを記述します。

render() {
    return (
        /*
            レンダーするDOMを記述する。
            作成した子コンポーネントもこの中で宣言して使う。
        */
    )
}

"Chat"としてimportした子コンポーネントを呼び出す方法は以下の通りです。
例...TextInputコンポーネントを呼び出す。

return(
    <Chat.TextInput />
)

さらに、引数を渡してみましょう。

src/templates/Chat.js
return(
    <Chat.TextInput
        onChange={this.props.actions.messages.change}
        value={this.props.messages.value}
    />
)

少し分かりづらいかもしれませんが

  • this.props.actions.messages.changeというActionsonChangeとしてTextInputコンポーネントに渡している
  • this.props.messages.valueというGlobal StateをvalueとしてTextInputコンポーネントに渡している

これによって、TextInputコンポーネントではprops.onChangeprops.valueとして渡された値を参照できる。

ライフサイクルメソッド

ReactのClass Componentsではライフサイクルメソッドが使えます。
ライフサイクルメソッドが分かりやすく図解されている記事はコチラ

代表的なメソッドは以下。

  • componentWillMount() --> 現在は非推奨なので使わない。
  • render() --> Viewを描画する。
  • componentDidMount() --> API連携など、通信が必要な処理はここで。
  • componentDidUpdate() --> stateが変更されて再render()が走った後に
  • componentWillUnmount() --> componentDidMount()で確保したリソースを解放する

src/templates/Chat.jsでは各メソッドで以下の処理を実行している。

  • componentDidMount() --> Firebase DBにメッセージのデータが追加されたらViewを再描画するようにリスナーを仕掛ける。
  • componentDidUpdate() --> メッセージ一覧の最下部にスクロールする。
  • componentWillUnmount() --> Firebase DBへのリスナーを解除する。

ソースコード載せると長〜いので、Githubを確認してください?

リスナーの設定はfirebase.database().ref().on()で。
逆にリスナーの解除はfirebase.database().ref().off()です。

リスナー設定/解除の詳細はFirebaseクライアントSDKのドキュメントを参照。
データの取得|Firebase Realtime Database

containersファイルの作成

最後にContainer Componentsを作成します。

src/containers/Chat/Main.js
import ChatTemplate from '../../templates/Chat';
import {bindActionCreators, compose} from 'redux';
import {connect} from 'react-redux';
import {actions} from '../../modules/chat/index';

const mapStateToProps = state => {
  return {
    messages: state.messages,
  };
};

const mapDispatchToProps = dispatch => {
  return {
    actions: {
      messages: bindActionCreators(actions.messages, dispatch),
    },
  };
};

export default compose(
  connect(
    mapStateToProps,
    mapDispatchToProps
  )
)(ChatTemplate);

すでに説明した通り、Container Componentsの役割は中継役です。

ReactとReduxを繋げるreact-reduxというライブラリのconnectメソッドを使います。

connectメソッドは、以下2つをReactコンポーネントで参照できるようにしているイメージです。

  • mapStateToProps: Reduxで管理しているstate(状態)
  • mapDispatchToProps: state(状態)を変更するためのReduxのActions

上記のContainer Componentsの書き方は汎用的に使えるはずです。

まとめ

Reactだけならまだしも、Reduxが絡むと途端にややこしくなります。

特にContainer Componentsconnectするあたりは、最初何をやっているのか全く理解できませんでした。

分からなくてもコピペしておきましょう。
この記事で少しでも理解を深めていただければ幸いです。

Reactは公式のドキュメントが充実しているので、(自戒も込めて)よく読んだ方がいいですね。

[次の記事]でははいよいよReduxのActions, Reducers, Storeなどを解説していきます。

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

フロント初心者がGatsbyでBlogを公開・運用するまで ~プロジェクト作成から公開の確認編~

はじめに

フロント初心者がGatsbyで試行錯誤しながら、Blogを作成・運用したのでそのまとめです。
Gatsbyの使い方からNetlify CMSを使った公開・運用までを2~3回に分けて書いていきたいと思います。

Blog作成の経緯

元々、「Gatsbyって凄いらしいし、使ってみたいなぁ。」とは思っていましたが、作りたいと思えるものがなかったため、特に何もせず1年が終わろうとしていました。
そんな中お正月に実家に帰省すると、母から「Blogを始めたいんだけど、どうすればいい?」と言われたのをきっかけに「じゃあ、ホームページ兼Blogを作ったるよ!」という話になったのがきっかけです。

Gatsbyって何?

Gatsby.jsはReactベースの「静的サイトジェネレーター」の一つでコンテンツ管理システムの一種です。
コンテンツ管理システムとして有名なWordPressとの大きな違いは、ビルド時にHTMLを生成して、リクエストを返却します。
詳しくは『Reactベース静的サイトジェネレータGatsbyの真の力をお見せします』こちらの記事が非常に分かりやすくてオススメです!

Gatsbyのインストール

まずはGatsbyのインストールをしていきます。
npmyarnによって、微妙にインストール方法が違います。
今回は個別のプロジェクト内だけで使用するわけではないので、globalを指定してインストールしていきます。

# npm 
$ npm install --global gatsby-cli
# yarn
$ yarn global add gatsby-cli

インストールが完了しているはずなので、Versionを確認していきます。
下記のようにVersionが確認できれば、Gatsbyの準備はOKです。

# 表示されるVersionは個々人で異なります。
$ gatsby --version
Gatsby CLI version: 2.8.22
Gatsby version: 2.13.33

Gatsbyの開発環境構築

GatsbyCLIの準備ができたので、LOCAL環境の開発環境を構築していきます。
Gatsbyの開発環境構築は大きくわけて、Githubリポジトリを指定する方法と指定しない方法の2通りがあります。

# Githubパスを指定しない方法
$ gatsby new sample
info Creating new site from git: https://github.com/gatsbyjs/gatsby-starter-default.git
...
...
success Saved lockfile.
✨  Done in 15.59s.
info
Your new Gatsby site has been successfully bootstrapped. Start developing it by running:

  cd sample
  gatsby develop

Githubパスを指定しない方法では、自動的にgatsby-starter-default.gitのパスが指定されてLOCALにフォルダが作成されます。
これだけでも十分に簡単にプロジェクトを始めていくことができますが、自分の目的にあったStarterを選択することで、より簡単にプロジェクトを開始することができます。
Starterは『Starter Library - Gatsby.js』から好きなものを選ぶことができます。
今回は、NetlifyCMSでHostingする予定なので、『gatsby-starter-netlify-cms』を使っていきます。

# Githubパスを指定する方法
$ gatsby new sample https://github.com/netlify-templates/gatsby-starter-netlify-cms
info Creating new site from git: https://github.com/netlify-templates/gatsby-starter-netlify-cms
...
...
success Saved lockfile.
✨  Done in 15.59s.
info
Your new Gatsby site has been successfully bootstrapped. Start developing it by running:

  cd sample
  gatsby develop

指定パスからプロジェクトが作成されていることを確認できます。
あとは指定の通り、cd sampleでプロジェクトのフォルダに移動して、 gatsby developのコマンドを実行し、localhost:8080にアクセスするだけです。
localhost-8080.png

ほとんど、CLIでコマンドを叩いているだけですが、こんな素晴らしいサイトが出来上がっています。
後は自分の好みに合わせて作り込んでいくだけです。

静的サイトのHosting

[Netilfy CMS側の準備]

次に静的サイトのHostingを行っていきます。
今回は、Netlify CMSを使っていきます。
Netlify CMSを初めて使うので、最初はお試しでGetting Startの内容に沿って、Hostingしていきます。

:bangbang::bangbang:注意:bangbang::bangbang:
NetlifyCMSを使ってHostingする場合には、NetlifyCMS用のStarterを選択するか、Pluginを追加する必要があります。
これを飛ばして作業を進めてしまうと/adminにアクセスできず、記事の投稿などをすることができないため、CMSとして役割を果たすことができません。
(Githubへ直接Pushするという方は問題ありません!!)

Netlify CMSへリポジトリの登録

まずはNetlify CMSとGithubの連携を行います。
(Githubに登録していない人は、Githubの登録から始めましょう!)

Netlify CMSに移動します。
netlify-start.png

[GET STARTED]をクリックします。
netlify-getstart.png

今回は、GatsbyのプロジェクトをHostingしていくのでGatsbyロゴの下にある、[Deploy to netlify]を選択します。

github-conn.png

Githubの連携を求められるので、[Connect to Github]を選択して、Githubと連携します。

net-githubrepo-new.png

次に進むとHosting用のリポジトリを作成するように促されるので、リポジトリを作成します。リポジトリを作成すると、管理画面へ自動的に移動します。
・・・
・・

最低限のHostingに必要な作業はこれだけです。

sample-hositing.png

新規で作成されたリポジトリを元にして、すでにサイトがHostingされています!
次は自作したプロジェクトのHostingを行っていきます。

Githubにリポジトリの作成とPush

[LOCAL環境準備]

Githubにリポジトリがないことには、何も始まらないので、兎にも角にもまずはリポジトリを作成します。
リポジトリができたら、RemoteをLOCALのリポジトリへ登録していきます。
その後に今回作ったプロジェクトをGithubへPushします。
gatsby newを実行した時点でLOCALのリポジトリは作成されているので、Push対象のRemoteを追加します。

# Remoteリポジトリの追加
$ git remote add origin git@github.com:atEaE/gatsby-blog-inaoka.git
# RemoteへPush
$ git push origin master

[Netlify CMSの準備]

Nelify CMSの準備といっても特別なことは特にしません。
最初に登録したリポジトリを使うか、後から登録したリポジトリを使うかの違い程度です。
まずは、[New site from Git]をクリックして、連携するサイトを選択します。
new-site.png

今回は、Githubにリポジトリを作成しているので、[Github]を選択します。

connect-repo.png

最初と同様に連携を求められるので、そのまま勧めていくとリポジトリの選択画面に移ります。
すべてのリポジトリをInstallしても構いませんが、時間がかかるので、Only select repositoriesにチェックをいれ、リポジトリを選択しましょう。

one-select.png

後は、Buildコマンド、公開用のフォルダを指定してあげればOKです。

deploy-setting.png

今回はGatsbyを使用しているのgatsby buildが選択されていることを確認します。
公開用のフォルダルートは個々人によって異なるとは思いますが、Gatsbyのプロジェクトを使っている方はほとんどの人が public/になるかと思います。

後はDeployされたサイトへのアクセスを確認します。

sample-hositing.png

確認できたので、ひとまずHostingの確認は完了です。
本当はカスタムドメインの設定、HTTPSのために証明書の設定等を行う必要がありますが、今回はここまでとします。

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

React初心者めちゃくちゃHelloWorldする

概要

React初心者によるReact初心者のためのReact勉強メモです

2020/01/03 Happy New Year :smile:
・ノーマルHello World
・関数コンポーネントHello World
・クラスコンポーネントHello World

導入

Create React Appを使用して環境構築を行います
npmのバージョンが5.2以上であればnpxがデフォルトで入っているはずなので下記で導入ができます

npx create-react-app my-app
cd my-app
npm start

Sass & Scss 導入

こちらの記事を参考にnode-sassを導入してsassを使えるようにしました

①まずはノーマルのHello world!

/src/index.jsを下記の様に書き換えてください。

/src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './sass/index.scss';

const say = 'Hello, World!';

ReactDOM.render(
  <div>
    <h1>{ say }</h1>
  </div>,
  document.getElementById('root')
);

ポイント

  • ReactReactDomをimportしていないと怒られます
  • ReactDom.render内で、表示するDOMを定義しています
  • getElementで取得しているid="root"というDOM内に追加されます
  • ReactDom.renderで返されるDOMは1つDOM要素である必要があります
    今回は1つの<div>要素を返していることになります
  • 3行目のimport './sass/index.scss';でscssを読み込んでいます
    /src/sass/のディレクトリにindex.scssを作成して、背景色等を変更し、変更が適用されるか確認してみましょう
/src/sass/index.scss
body {
    background: #f2f2f2;
}

表示結果

上記の様に実装すると、このように表示されるはずです :yum:
image.png
変数sayに入れる文言を変更してみて、表示される内容が変わるか試してみてください!

②関数コンポーネントでHello World!

今度は/src/index.jsを下記の様に書き換えてください。

/src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './sass/index.scss';

const say = 'Hello, World!';

// 関数コンポーネント
function Hello(props) {
  return <h2>Hello, {props.name}!</h2>;
}

ReactDOM.render(
  <div>
    <h1>{ say }</h1>
    <Hello name="hoge" />
  </div>,
  document.getElementById('root')
);

ポイント

  • 関数コンポーネントとは文字通り、関数によって作られたコンポーネントです
    render内で呼び出す際には関数名を呼び出します
  • 関数コンポーネントは引数としてpropsを受け取ります
    render内で呼び出しの際に記述しているname="hoge"props.nameで使用できます
  • render内で記述されるタグは頭文字が小文字の場合DOM要素・頭文字が大文字の場合コンポーネントとして認識されます

表示結果

上記の様に実装を行うとこのように表示されるはずです

image.png

Helloコンポーネントを呼び出している箇所で渡す名前を自分の名前に変更してみてください
挨拶してくれるはずです :smile:

③クラスコンポーネントでHello World!

今度は/src/index.jsを下記の様に書き換えてください。

import React from 'react';
import ReactDOM from 'react-dom';
import './sass/index.scss';

const say = 'Hello, World!';

// クラスコンポーネント
class Hello extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      name: 'Bob'
    }
  }

  setName = (e) => {
    this.setState({
      name: e.target.value
    });
  }

  render() {
    return (
      <div>
        <h2>Hello, {this.state.name}!</h2>
        <label for='name'>input your name!</label>
        <input type='text' onChange={this.setName} />
      </div>
    );
  }
}

ReactDOM.render(
  <div>
    <h1>{ say }</h1>
    <Hello />
  </div>,
  document.getElementById('root')
);

ポイント

  • クラスコンポーネントは独自のstate(状態)を持つことができます
  • stateを使用する場合にはコンストラクタが必須になり、このコンストラクタ内でstateの初期値を設定します
    また、このコンストラクタでは必ず引数にpropsを受け取り、super(props)を行う必要があります
  constructor(props) {
    super(props);
    this.state = {
      name: 'Bob'
    }
  }
  • stateは直接変更をしてはいけません
    今回の場合は<input type='text' onChange={this.setName} />this(コンポーネント内の).setName
    呼び出して、その関数内でsetStateを使用してstateを変更しています
  setName = (e) => {
    this.setState({
      name: e.target.value
    });
  }
  • クラスコンポーネント内のrender()で返却するDOM要素を定義しています
    ここでもDOM要素を1つで返す必要があるので、<div>で囲っています
  • コンポーネント内のstateをDOM要素内で取得する場合は{this.state.name}というように記述します
  render() {
    return (
      <div>
        <h2>Hello, {this.state.name}!</h2>
        <label for='name'>input your name!</label>
        <input type='text' onChange={this.setName} />
      </div>
    );
  }

表示結果

上記の様に実装を行うとこのように表示されるはずです
react-test.gif
名前を入力して変更されるか試してみてください :smile:

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

React/Next.jsアプリケーションを作成し、AWS EC2を使って本番環境にデプロイするまで

対象

  • Next.js 等、Node.js で動かすアプリをローカル環境で作成することはできるが、それを本番環境で動かす方法と仕組みがわからない人
  • Heroku や Zeit Now を使うと簡単にリリースできるが、その仕組がさっぱりわかっていない人

この記事の存在意義

初心者が掲題のことをやろうと思ったときに、全体感を把握できる記事が見当たらなかったので、こういう記事があっても良いかなと思った。

流れ

以下のような手順で進める。
1. ローカル環境で動く Next.js を用いたサンプルアプリの作成
2. EC2 インスタンスの作成
3. EC2 インスタンス上でのサンプルアプリの起動&接続

1. ローカル環境で動く Next.js を用いたサンプルアプリの作成

  • 事前に npm をインストール
npm install -g npm

2. EC2 インスタンスの作成

公式に従ってやっていく。
自分の環境から ssh できるようにしておき、かつ http 通信はできるようにしておく。

3. EC2 インスタンス上でのサンプルアプリの起動&接続

3.1 外部アクセスをローカルホストにつなげるようにする

外部からアクセスがあったときに、そのアクセスをサンプルアプリが受け取って結果を返さなければならない。
しかしここまでのところ、localhost:3000 でアプリケーションを起動することしかできていない
そこで、「外部からのアクセスを受けたらそれをローカルホストにつなげるような仕組みを用意する」ことにする。

nginx を使ってそれを実現する。すなわち、「nginx をリバースプロキシとして用い、ポート80へのアクセスをlocalhostの3000ポートに振り向ける」ようにする。

  • ssh で EC2 インスタンスに入る。
ssh -i <key.pem>  <public ip address>
  • nginx の install
sudo su - root
yum update -y
yum install nginx -y

↑これを実行すると、nginx の install 時に Amazon Linux 2だとエラーになる。

Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
No package nginx available.
Error: Nothing to do


nginx is available in Amazon Linux Extra topics "nginx1.12" and "nginx1"

To use, run
# sudo amazon-linux-extras install :topic:

Learn more at
https://aws.amazon.com/amazon-linux-2/faqs/#Amazon_Linux_Extras

エラーメッセージの指示に従う。

sudo amazon-linux-extras install nginx1.12
  • nginx の起動
sudo systemctl start nginx.service

この時点で、ブラウザからアクセスすると以下のような状態になっているはず。

スクリーンショット 2020-01-03 4.09.47.png

  • nginx の設定変更(リバースプロキシの設定)
# 〜省略〜
http {
    # 〜省略〜
    server {
        # 〜省略〜
        location / {
            # 以下の行を追加
            proxy_pass http://localhost:3000;
        }
        # 〜省略〜
    }
}

この1行を追加することにより、ローカルホストの port:3000 に向けることができるようになる。ただし、nginx の設定を反映させるために nginx を再起動させることを忘れてはならない。

  • nginx の再起動
sudo systemctl restart nginx

この時点で、ブラウザからアクセスすると以下のような状態になっているはず。
スクリーンショット 2020-01-03 4.18.37.png

これはまだサンプルアプリを起動しておらず、振り向けた先から応答が返ってこないから。

3.2 サンプルアプリの起動

  • ssh で EC2 インスタンスに入る(既に入っていればそのままでOK)。
ssh -i <key.pem>  <public ip address>
  • git の install
sudo yum -y install git
vim ~/.ssh/id_rsa  # 自分のローカルのものをコピーしてくる
chmod 400 ~/.ssh/id_rsa
git clone https://github.com/<your sample app repository>
  • npm/node の install(公式のダウンロード方法はこちら)
sudo su - root
curl -sL https://rpm.nodesource.com/setup_13.x | bash -
yum install -y nodejs
  • 確認
$ npm -v
6.13.4
$ node -v
v13.5.0
  • アプリケーションのビルド
cd <your repository>
npm install
npm run build
  • アプリケーションの実行
npm run start

ブラウザから見てみると、以下のように適切に表示されているはず!

スクリーンショット 2020-01-03 4.19.03.png

まとめ

個人開発の際、なるべく早めに本番環境へのデプロイができることを確認しておくと、(不慣れな方は特に)不確実性を(そして心理的不安を)大きく減らすことができるかと思います。
まだ問題の切り分けを行いやすい最初のうちにこそ、本番環境でのデプロイを一度試してみることをおすすめします。

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