20210322のReactに関する記事は9件です。

React+Reduxについて簡単に解説してみた

初めに(前書き)

最近では、Reactが3大Webフレームワーク(=Vue&React&Angular)の中で、抜きに出ているとのことですが、いかんせん、浅学非才の私には(一般的に用いられる)ReactとReduxを組み合わせたシステムの構成や全体の動作が把握しづらいです・・・(泣)。したがって、(勝手ながら)この記事は、ReactとReduxについて学び始めた(自分と同じ立場の)方を対象にしたいと思います。

本題(本文)

概説としては、ReactはWebアプリケーションのヴューを担当し、Reduxはモデルないしヴューモデルを担当します。※ちなみに、「ヴューモデル」とは、MVCに取って代わられるであろう「MVVM(Model-View-ViewModel)」と呼ばれるアーキテクチャーの構成要素です。

Reactでは、「コンポーネント」と呼ばれる単位でヴューを構成します。※ここでいう「ヴュー」とは、(大雑把にいえば)Webページのことです。
このコンポーネントは、jsファイル(やjsxファイル)に記述されます。このファイル内では、ヴューを構成する各コンポーネントに対応するrender関数内でタグ(やカスタムタグ)を書いて、これを呼び出し元にreturnします。こうすることで、実際のヴューが形作られて、描画されていきます。

Reduxでは、前述のコンポーネントに「ステート」と呼ばれる特定の状態があって、ユーザーからの入力(=インタラクション)などによって起こるステートの変化を読み取って、これをヴューに反映させます。さらには、ステートに変更があった場合に、その変更を自動的に検知して、ヴューに対して、変更された内容の伝達および、更新の依頼をします。

従来のMVCアーキテクチャーでは、(通常は、)コントローラーがユーザーからの入力を受け付けて、モデル(≒ステートの集まり)(≒「Store」)の内容を参照し、その内容をヴューに伝達すると共に、ヴューに更新を依頼するという流れであり、これがMVC全体の仕組みでしたが、このヴューの更新を自動化することがMVVMの特徴であり、強味なのです。

終わりに(後書き)

ReactとReduxを組み合わせたシステムは、私の想像以上に複雑で、ここでは簡単に解説させていただきましたが、実際には、「Action」「ActionCreator」「Store」「Container」「Reducer」・・・などといった構成要素・概念が絡んでくるので、・・・(私の非力ゆえに)割愛させていただきました(笑)。また、あまりゴチャゴチャとした解説では、却って、わかりづらくなるかとも思いましたので・・・(言い訳)。

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

Vite+React+Typescriptでimportのパスを必要最低限にする

Viteを使用してReact+Typescriptのプロジェクトの開発をしています。
Typescriptのimportのパスに../のような相対パス指定を指定したくなくて、必要最低限の指定で利用できないものかと考えていました。
ほんのわずかなコードでも、コードが小さければ不具合はそれだけ減らせるからです。

そこでtsconfig.jsonにcompilerOptions.baseUrlの設定をしたものの、Viteはその設定を読んでくれませんでした。
Viteにはvite.config.tsという設定ファイルがあるのでそこに設定をしなければならないようです。

私のプロジェクトでは、アトミックデザインを採用しています。

tsconfig.jsonの例

baseUrlを書くと相対パスの指定がない場合にどこを起点にパスを解決するかを指定できます。
ここでは"src"としています。
pathsという設定もあるのですが、それもViteは読み込まないようです。

{
  "compilerOptions": {
    "target": "ESNext",
    "lib": ["DOM", "DOM.Iterable", "ESNext"],
    "types": ["vite/client"],
    "allowJs": false,
    "skipLibCheck": false,
    "esModuleInterop": false,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "module": "ESNext",
    "moduleResolution": "Node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react",
    "baseUrl": "src"
  },
  "include": ["./src"]
}

vite.config.tsの例

tsconfig.jsonに書いたbaseUrlやpathsはViteは読んでくれません。
そこでvite.config.tsは以下のようにエイリアスを設定します。

import * as path from "path"の部分がエラーになる方は、yarn add @types/node -Dnpm -i -D @types/nodeを実行してください

import { defineConfig } from "vite"
import reactRefresh from "@vitejs/plugin-react-refresh"
import * as path from "path"

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [reactRefresh()],
  resolve: {
    alias: {
      "atoms": path.resolve(__dirname, "src/atoms"),
      "molecules": path.resolve(__dirname, "src/molecules"),
      "organisms": path.resolve(__dirname, "src/organisms"),
      "templates": path.resolve(__dirname, "src/templates"),
      "pages": path.resolve(__dirname, "src/pages")
    }
  }
})

import文はどうなる?

ディレクトリー構成は以下のようになっているとします。

:
├ pages
│ ├ index.ts
│ └ HomePage.tsx
├ templates
│ ├ index.ts
│ └ MainTemplate.tsx
:

index.tsは以下のようになっているとします。

import MainTemplate from "templates/MainTemplate"

export { MainTemplate }

import文は以下のように指定すれば、必要最低限の指定でコンポーネントを呼び出せます。

import * as React from "react"
import { MainTemplate } from "templates"

export default () => (
  <MainTemplate>
    コンテンツ
  </MainTemplate>
)

注意

  • 本プロジェクトで使用しているViteのバージョンは2.1.2です。バージョン1系だと、vite.config.tsの書き方が違う可能性があるのでご注意ください。
  • 指定したエイリアス以外のディレクトリーが必要になったときは、vite.config.tsにメンテナンスが必要になりますが、そのようなことが起こることはあまりない前提です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Amplify×Lambda×SESでメール配信

概要

開発中のアプリにレポートを投稿した際にメール通知が必要ということでAWSのSESを利用した検証を行いました。
メール通知やメール配信を考えている方の少しでも参考になればと思います。

事前に

アプリケーション

Amplify SNS Wrokshopの「FOLLOW/TIMELINE機能の実装」までを実装済みの方を前提としています。
しかし、SESの実装自体は簡単ですので、Amplify SNS Wrokshopをやっていない方でも実装できると思います。

Email認証

SESの送信元は検証済みのEメールアドレスが必要となります。
検証済みのEメールアドレスがない方はこちらを参考に準備してください。

実装

権限設定

LambdaにSESの権限を与えるにはamplify/backend/function/createPostAndTimeline/createPostAndTimeline-cloudformation-template.jsonを編集します。
lambdaexecutionpolicy>PolicyDocument>Statement>Actionにses:SendEmailses:SendRawEmailを追加します。

    "lambdaexecutionpolicy": {
      "DependsOn": [
        "LambdaExecutionRole"
      ],
      "Type": "AWS::IAM::Policy",
      "Properties": {
        "PolicyName": "lambda-execution-policy",
        "Roles": [
          {
            "Ref": "LambdaExecutionRole"
          }
        ],
        "PolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Effect": "Allow",
              "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents",
                "ses:SendEmail", // Here!
                "ses:SendRawEmail" // Here!
              ],
              "Resource": {
                "Fn::Sub": [
                  "arn:aws:logs:${region}:${account}:log-group:/aws/lambda/${lambda}:log-stream:*",
                  {
                    "region": {
                      "Ref": "AWS::Region"
                    },
                    "account": {
                      "Ref": "AWS::AccountId"
                    },
                    "lambda": {
                      "Ref": "LambdaFunction"
                    }
                  }
                ]
              }
            }
          ]
        }
      }
    },

AWS SDKのインストール

AWS SDKをamplify/backend/function/createPostAndTimeline/srcにインストールします。

cd amplify/backend/function/createPostAndTimeline

npm install aws-sdk

送信処理

ここからamplify/backend/function/createPostAndTimeline/src/index.jsに送信処理を加えていきます。

まずは、AWS SDKを読み込みます。

const AWS = require("aws-sdk")

さらに、フォロー処理の下あたりに処理を加えます。 

1.送信するEmailのparamsを設定
2.リージョンを設定
3.送信処理

exports.handler = async (event, context, callback) => {
・
・
・
const listFollowRelationshipsResultWithOwner = await graphqlClient.query({
        query: gql(listFollowRelationships),
        fetchPolicy: 'network-only',
        variables: queryInput,
});

// 1.送信するEmailのparamsを設定
const params = {
    Destination: {// 必須
     CcAddresses: [
       'EMAIL_ADDRESS',
     ],
     ToAddresses: [
       'EMAIL_ADDRESS',
     ]
    },
    Message: { // 必須
      Body: { // 必須
        Text: {
          Charset: 'UTF-8',
          Data: `投稿内容:${res.data.createPost.content}\n投稿日時:${new Date(res.data.createPost.timestamp)}`,
        },
      },
      Subject: {
        Charset: 'UTF-8',
        Data: '投稿しました'
      },
    },
    Source: 'SENDER_EMAIL_ADDRESS', // From・必須
}

// 2.リージョンを設定
AWS.config.update({ region: "ap-northeast-1" })

// 3.送信処理
const ses = new AWS.SES()
try {
    await ses.sendEmail(params).promise()
    console.log("Success to Send an Email")
    return
} catch (e) {
    console.log(`Failed to Send an Email: ${e}`)
    return
}

  return post;
};

送信結果

アプリを起動して、投稿をするとメールが届きました!
test.png

まとめ

今回はSESでメールの送信を実装しましたが、Lambdaに権限を追加すれば他のAWSのサービスも利用できそうです。
SESには、今回使っていない設定やテンプレートなどがあるようなので、カスタマイズしたい方はこちらを参考にしてみてください。

参考

使用した E メールの送信Amazon SES
Lambda と Amazon SES を使用して E メールを送信するにはどうすればよいですか?



- Miyata Koki -
O:inc.でAmplify×React×React Nativeを使用して開発しています。大学のゼミでは統計学をPythonで行っています。
インターンやゼミで学んだ情報を発信していくので、フォロバするのでぜひこちらのアカウントのフォローお願いします!

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

ProxyベースのReact状態管理ライブラリ「Valtio」v1リリース

Valtioがv1.0.0になりました! :tada:

ぜひ試しにでも使ってみてください。

基本的に不具合等の対処が一通り終わって安定してきたのでv1になったのですが、一つだけ隠し機能だったものがオープンになりました。

useProxyマクロ

v0.7.1まではuseProxyは本体から提供されていましたが、v0.8.0からはuseSnapshotに改名しました。中身は変わっていません。

代わりにuseProxyはマクロとして提供されるようになりました。babel-plugin-macrosを使っているのですが、Create React Appを使っている場合はすでに組み込まれています。

このuseProxyマクロを使うと、

import { useProxy } from 'valtio/macro'

const Component = () => {
  useProxy(state)
  return (
    <div>
      {state.count}
      <button onClick={() => ++state.count}>+1</button>
    </div>
  )
}

と言うコードが、次のように変換されます。

import { useSnapshot } from 'valtio'

const Component = () => {
  const snap = useSnapshot(state)
  return (
    <div>
      {snap.count}
      <button onClick={() => ++state.count}>+1</button>
    </div>
  )
}

useProxyマクロを使うと、snapshotをほとんど意識せずにコーディングすることができます。snapshotの概念がなくなるわけではありませんが、snapshotの扱いは癖があるので、マクロが使えるケースでは役立つでしょう。ちなみに、eslint-plugin-valtioもあります。

おわりに

valtioのv1リリースが完了したので、次はjotai。こっちは大物。
https://github.com/pmndrs/jotai/issues/333

React開発者向けオンラインサロン「React Fan」の紹介

最後に、私が主催している「React Fan」というコミュニティをお知らせします。テキストチャットでコミュニケーションできるSlackのワークスペースを用意しています。Slackへの参加は無料ですので、ご興味がある方はぜひご参加ください。詳しくは、下記のページをご参照ください。

React開発者向けオンラインサロン「React Fan」の入り口ページ

Slackへの招待リンクも上記ページにあります。

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

DjangoとReactで作成したアプリにDockerを組み込む

Dockerとは

一言で言うとコンテナ型のアプリケーション実行環境のこと。
DockerがあればどのPCからでも、簡単にそのアプリを実装できる環境を構築することができる。

今回やること

前回私が開発したアプリにDockerを組み込んで環境構築を容易にしていく。

そのアプリの開発記事↓
DjangoとReactでPDCAアプリを作る その1

作業の流れ

1.requirements.txtの作成

2.Django用Dockerfileの作成

3.nodejs用Dockerfileの作成

4.docker-composeの作成

requirements.txtの作成

完成したアプリのディレクトリ下で以下のコマンドを実行するとそのアプリでインストールしたライブラリをrequirements.txtにまとめることができる

pip freeze > requirements.txt

なお、アプリ開発を行うにあたってVirtualenvを使って、専用の開発環境を準備した方が良い。
そうしてから取り組めば、そのアプリ開発でインストールしたライブラリだけをrequreiments.txtに落とし込むことができる。

virtualenvについての記事↓
venv: Python 仮想環境管理

Django用Dockerfileの作成

# pythonの基本的な環境をubuntuで構築している↓↓
FROM ubuntu:18.04
RUN apt-get -y update \
    && apt-get -y upgrade \
    && apt-get install -y locales curl python3-distutils \
    && curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py \
    && python3 get-pip.py \
    && pip install -U pip \
    && mkdir /code \
    && rm -rf /var/lib/apt/lists/* \
    && localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8
ENV LANG en_US.utf8
# ↑↑


# 作成したrequirementsをコンテナ側へcopy
COPY ./requirements.txt /requirements.txt

# コンテナ側でアプリに必要なライブラリをインストール
RUN pip install -r /requirements.txt

# アプリを置くためのディレクトリを作成
RUN mkdir /workapp

# 起動時に最初に開かれるディレクトリを設定
WORKDIR /workapp

# 作成したアプリをコンテナ側へcopy
COPY ./workapp /workapp

nodejs用Dockerfileの作成

FROM node:10.13-alpine

docker-composeの作成

docker-composeとは、

dockerでこのコンテナを立てる際に使うであろうdockerコマンドを1つのファイルにまとめてくれるツール

version: '3'

services:
  app:
    build:
      context: .
    tty: true
    stdin_open: true
    ports:
      - "8000:8000"
    # コンテナ側から実際の環境側にあるアプリを参照する
    volumes:
      - ./workapp:/workapp
    command: >
      sh -c "python3 manage.py migrate &&
             python3 manage.py runserver 0.0.0.0:8000"
    depends_on: 
      - react
  react:
    build:
      context: .
      dockerfile: "./Dockerfile-nodejs"
    volumes:
      - ./work_react:/work_react
    command: >
      sh -c "cd work_react && npm start"
    ports:
      - "3000:3000"

dockerを起動してアプリディレクトリ下で、以下のコマンドを実行する

docker-compose up

これで無事、djangoとReactで開発したアプリにDockerを組み込むことができた?

今後の展望

今回は、DBをsqliteのままにしてDockerを組み込んだので、次回は、postgresSQLを用いて組み込めるようにしたい。
また、nginx等のwebサーバーも用いて、開発現場さながらのDockerコンテナを作成したいと考えている

ここまで読んでくださりありがとうございました?‍♂️?‍♂️

また、Twitterでも日々の積み上げや、プログラミング学習についてのツイートをしておりますので、よかったらフォローと応援の程よろしくお願いします!?‍♂️

Twitterアカウント↓
健将@WEBエンジニア×明大生

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

ポートフォリオ(チャットアプリ)について

どんなアプリか

『業務連絡のレスが早い人ほどポイントが貯まる(仕事のできる信頼が可視化される)チャットアプリ』

  • メールアドレスでのユーザー登録機能
  • 個人間でのチャット機能
    • コンタクトを承認し合わないとメッセージ送受信できない
    • 承認し合ったユーザーのみチャットリストに表示される
  • リアルタイムでユーザーがオンラインかオフラインかがわかる機能
  • 相手の任意で送られてくる”即レスしてほしいメッセージ”に1時間以内に返信することでポイントが加算される機能
  • リアルタイムで更新されるユーザー情報の事前検索機能

チャットアプリ(QuickDonut)URL

GitHubレポジトリURL

なぜこのアプリを作ったか

昨今特にリモートワークがうたわるようになったビジネスシーンにおいて、メールの返信が早い事は、一つの信頼になります。
逆に返信が遅いというのは、コミュニケーションの流れが止まり、ビジネスも停滞してしまうので良くありません。
この事実を裏付ける根拠として、あらゆるビジネスパーソンの方が「即レス」の重要性を仰っています。
https://mynavi-agent.jp/dainishinsotsu/canvas/2021/01/4-1.html#sec5
https://ameblo.jp/nishino-akihiro/entry-12608672747.html
https://note.com/bookadviser/n/n13a3f84a2fbe
https://www.lidix.co.jp/blog/entry/2020/07/09/073000/6/
https://fuantensyoku.com/me-ru-hensin-osoi/
これだけ語られている議論であるのに、まだ具体的な解決に至っていないのはなぜか、どこに問題があるかを考え、解決策の一つの提案としてこのアプリを作りました。

この問題のネックは、返信が早い人に明確なうまみが少ないことと、事前に返信が早い人が可視化されないことにあると考え、
逆にこの二つをクリアにするコミュニケーションツールがあれば、この問題を解決できるのではないかと仮説を立てました。
円滑なリモート・コミュニケーションが取れれば、仕事もスムーズにすすむ。
ただ、やはり返信が早い人もいれば遅い人もいる。そして、早いかどうかは一緒に実際に仕事をしてみないとわからない。
そこで、
即レス力が事前に分かりさらに返信が早いほどポイントが貯まるシステムにすれば、

1. 一緒に仕事をする前や、採用時に、相手の返信の早さが分かり、
2. さらに逆の立場からだと、返信の早さをアピールする材料にできる、

そしてそのシステムによって、

3. 普段あまり返信が早くない人でも、即レスを意識できる、

そしてこのアプリでそれらの問題を解決できれば、

4. 同じ会社内に限らず、社外提携や、フリーランスにまで、ビジネスの活性が広がるのではないか

と考え、開発に至りました。

どんな技術を利用したのか、またその理由

  • フロントエンド
    • React
    • React Router
    • React Redux
    • Redux Thunk
  • バックエンド
    • Firebase

自分の技術面での話になるのですが、僕はReactを使って簡単な自己紹介サイトは作れるようになったので、
次の段階として、今まで学習してきたRouter、Redux、Thunkを使って、データベースと絡んだSPAを作りたいと考えました。
手軽さとドキュメントの読みやすさ、情報の多さを考えて、バックエンド機能にFirebaseを使用することにすることにしました。
Firebaseを選んだ1番の理由は、DBの自動更新を検知する機能があり、それを応用して手軽にチャットアプリを作れるということを知ったからです。

開発過程ダイジェスト

まず、土台であるチャットアプリの作り方を学ぶため、いくつかのアプリを模倣して作ってみることにしました。

その他、

いくつか既存のものを真似ながらいくつか作ってみて、自分の思い描く実装にあった機能を取り入れながら、ポートフォリオの土台が完成。

次に、今回のメイン機能である返信が早いほどポイントが貯まるシステムですが、そのルール設定に少し悩みました。
早ければ早いほどポイントを高くしてしまうと、実際に使うときに競争感を覚え、息苦しさを感じる、
かといって、24時間以内とかにすると、本当に返信の早い人が正当に評価できないと考え、「1時間以内の返信で一律1ポイント」とルールを決めました。

そして全ての返信で即レスを促すのではなく、送信するユーザーが適宜、早く返信して欲しいと思うメッセージにユーザーの任意で「ポイントチャンス」を付与できることにしました。

当初はタイマーAPIを自作しようと考えていましたが、返信時間とその一つ前のメッセージの送信時間の時差を計算すれば、同期処理で簡単に済むことに気づき、
https://gray-code.com/javascript/calculate-the-difference-between-two-dates-and-times/
この記事を主に参考にして、返信時差が1時間以内であるかどうかを検知し、ポイントを加算するシステムを作りました。
そして、コンタクトの申請承認の前に、事前にその人のポイント情報などをリアルタイムで確認できる『ユーザー検索機能』
誰でもかれでもメッセージを送れてしまうと、ポイントシステムの秩序が乱れると考え、
『コンタクト承認し合わないとチャットできない機能』と、『承認したユーザーのみチャットリストに表示される機能』をさらに追加することに。
ここは腕試し的にかなり自己流で作ってしまったので、もしかすると他にもっと効率的なコードがあるはずであるのが、少し反省点なので、
今後、いろんなコードを参考にしながら、リファクタリングを進めて行こうと思います。

つまずいたところと、それをどう乗り越えたか

今後改善したい点、実装したい機能

実装したい機能

  • もっとユーザーの即レス力を正確にするため、週間での総オンライン時間、ポイント獲得数のデータ表示
  • 即レス時間はいいものの、その返信内容が適切だったかを判断するため、ポイント獲得時に相手から返信内容をGood/Bad/NothingSpecialで評価される(その総数もデータ表示)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【React】Reactで同じモーダルを使ってURLを振り分ける

前提

以下のように同じモーダルウィンドウを使って新規登録、ログイン、ログアウトの処理を実装したい
recommended-books-2-3.gif

結論

navigationを使うことで対応。

実装内容

①モーダルを開く処理をLinkごとに分ける

以下のように、新規登録・ログイン・ログアウトそれぞれモーダルを開くためのメソッドを切り分ける。
ここは引数を使うと楽な気がするが一旦このまま進める。

// 新規登録・ログイン・ログアウトでモーダルの表示を分けるために別メソッドとして定義
  openSignUpModal() {
    this.setState ({
      showModal: true,
      content: 'SignUp'
    })
    this.props.history.push("/users/sign_up");
  }

  openSignInModal() {
    this.setState ({
      showModal: true,
      content: 'SignIn'
    })
    this.props.history.push("/users/sign_in");
  }

  openSignOutModal() {
    this.setState ({
      showModal: true,
      content: 'SignOut'
    })
    this.props.history.push("/users/sign_out");
  }

  // モーダルを閉じる。contentは空文字列にリセット
  closeModal() {
    this.setState ({
      showModal: false,
      content: ''
    })
    this.props.history.push("/");
  }

②各モーダルを開くためのリンクにそれぞれのメソッドを設定する

<HeaderLink onClick={this.openSignUpModal}>
  新規登録
</HeaderLink>
<HeaderLink onClick={this.openSignInModal}>
  ログイン
</HeaderLink>
<UserModal show={this.state.showModal} close={this.closeModal} content={this.state.content} signIn={this.successToSignIn}/> {/* stateのcontentでログインと新規登録を分岐 */}

ログアウトボタンはログインしているときのみ表示

<HeaderLink onClick={this.openSignOutModal}>
  ログアウト
</HeaderLink>
<UserModal show={this.state.showModal} close={this.closeModal} content={this.state.content} signOut={this.successToSignOut}/> 

こうすることで各ボタンごとにstateの更新処理を分け、URLも別々にnavigationできる。
そしてstateの値に応じてモーダルの表示内容を切り替えることで快適なnavigationを実現

参考

navigationについて
https://qiita.com/TsutomuNakamura/items/34a7339a05bb5fd697f2#navigate

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

React基礎

Reactの知識定着の為の忘備録

PC: Mac

JSX

マークアップとロジックを両方含む疎結合の「コンポーネント」という単位を用いる為にReactがJavaScriptの構文を拡張したものである。
要は簡単にHTMLとJSを1つのプログラムを書く様に併用できるようにしたもの!
{}でJavaScriptの要素をHTMLに入れ込むことが可能

const name = 'Josh Perez';
//{}の中にJSを埋め込む
const element = <h1>Hello, {name}</h1>;
//出力:Hello, Josh Perez

ReactDOM.render(
  element,
  document.getElementById('root')
);

また関数や関数の結果も埋め込むことが可能

function formatName(user) {
  return user.firstName + ' ' + user.lastName;
}

const user = {
  firstName: 'Harper',
  lastName: 'Perez'
};

const element = (
  <h1>
  //userを引数にとり、formatName関数の返り値を取得
    Hello, {formatName(user)}!
  </h1>
);

JSXも式である為、if,for,変数に代入,引数,返り値等、柔軟に対応ができる

タグがからの場合は閉じタグを省略できる

const element = <img src={user.avatarUrl} />;

またJSXはレンダー前にエスケープされる為、インジェクション攻撃にも対応している
自分のアプリケーションで明示的に書かれたものではないあらゆるコードは、注入できないことが保証され、レンダーの前に全てが文字列に変換される。XSS (cross-site-scripting) 対策がされている。

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

Docker + React (Typescript) + Rails6 環境構築

Summary

バックエンド Rails API & フロントエンド React & Docker の環境を実現したので手順をメモしておく

  1. Rails 初期設定ファイル作成
  2. Rails & React 用のDocker関連ファイル作成
  3. docker-compose.yml 作成
  4. docker コマンド実行
  5. database.yml の変更
  6. docker-compose で起動

ファイル構成

image.png

1. Rails 初期設定ファイル作成

Gemfile
source 'https://rubygems.org'
gem 'rails', '=>6'
Gemfile.lock
# 空

2. Rails & React 用のDocker関連ファイル作成

Rails

Dockerfile
FROM ruby:2.7.2

# Rails6 からは以下のインストールが必要
# https://yarnpkg.com/lang/en/docs/install/#debian-stable
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \
  echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \
  apt-get update -qq && apt-get install -y nodejs postgresql-client vim && \
  apt-get install -y yarn && \
  apt-get install -y imagemagick && \
  apt-get install -y libvips-tools && \
  apt-get install -y locales

RUN curl -sL https://deb.nodesource.com/setup_7.x | bash - && \
    apt-get install nodejs

RUN mkdir /myapp
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
COPY . /myapp

COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

CMD ["rails", "server", "-b", "0.0.0.0"]
entrypoint.sh
#!/bin/bash
set -e

# Remove a potentially pre-existing server.pid for Rails.
rm -f /myapp/tmp/pids/server.pid

# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"

React

Dockerfile
FROM node:14.16.0-alpine3.10
WORKDIR /usr/src/app

3. docker-compose.yml の作成

docker-compose.yml
version: "3.9"

services:
  db:
    image: postgres
    volumes:
      - postgres-data:/var/lib/postgresql/data
    environment:
      - POSTGRES_PASSWORD=password

  api:
    build:
      context: ./api/
      dockerfile: Dockerfile
    command: /bin/sh -c "rm -f /myapp/tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - ./api:/myapp
      - ./api/vendor/bundle:/myapp/vendor/bundle
    environment:
      TZ: Asia/Tokyo
      RAILS_ENV: development
    ports:
      - 3000:3000
    depends_on:
      - db

  front:
    build:
      context: ./front/
      dockerfile: Dockerfile
    volumes:
      - ./front:/usr/src/app
    command: sh -c "cd frontend && yarn start"
    ports:
      - "8000:3000"

volumes:
  postgres-data:
    driver: local

4. docker コマンド実行

$ docker-compose run api rails new . --force --no-deps --database=postgresql --api
$ docker-compose build
# yarn でインストール、Typescript 対応
$ docker-compose run --rm front sh -c "yarn create react-app frontend --template typescript"

5. database.yml の変更

config/database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  username: postgres
  password: password
  pool: 5

development:
  <<: *default
  database: myapp_development

test:
  <<: *default
  database: myapp_test

production:
  <<: *default
  database: myapp_production
  username: myapp
  password: <%= ENV['MYAPP_DATABASE_PASSWORD'] %>

6. docker-compose で起動

$ docker-compose up -d
$ docker-compose run api rails db:create

参考

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