20190709のReactに関する記事は6件です。

変わらないReact VDOMをBabelで最適化

不思議なもので、少し前に悩んでいたことを解決するためのBabelプラグインにちょうどめぐりあうことができました。

JSXの中身

Reactを書くときに使うJSXですが、実際にJavaScriptとして処理する際にはReact.createElementという関数(リファレンス)に変換されます。

// before

(<p>
  文章
  <a href="https://qiita.com/">Qiita</a>
</p>)

// after

React.createElement("p", null, 
  "文章", 
  React.createElement("a", { href: "https://qiita.com/" }, 
    "Qiita"
  )
);

<br />のような表記を見ればリテラルのようにも思えますが、実態としては関数呼び出しになっています。さらに、React.createElementの中身は引数チェックをして、与えられた引数をオブジェクトに詰め込む程度のシンプルなもので、特にキャッシュなどはなされないので、<br />のようなごくシンプルなVDOMエレメントであっても、呼び出すたびに新しいものが作られます。

毎回生成するデメリット

もちろん、React.createElementは、本物のDOMの生成と比べれば、ずっと軽い処理です。とはいえ、全く同じ仮想DOMを何度も生成すると、以下のような点で無駄が発生します。

  • React.createElementの実行時間
  • 各回ごとに別なオブジェクトが生成するので、
    • メモリを消費し、ガベージコレクタにより負荷をかける
    • 比較しても一致しないので、そのVDOMを別なコンポーネントの引数にした場合にReact.memoが効かなくなる

自分が少し前にした投稿では、最後のデメリットが気になったのでした。

Babelで解決

何気なくBabelのChangeLogを読んでいたところ、@babel/plugin-transform-react-constant-elementsというプラグインの存在を知りました。これは、JSXが同じスコープ内の変数を使っていない場合に。できるだけ上位のスコープ(完全に何も変わらない場合はトップスコープ)まで引き上げる、というものです、

書かれていた例
// before
const Hr = () => {
  return <hr className="hr" />;
};

// after
const _ref = <hr className="hr" />;

const Hr = () => {
  return _ref;
};

手動でこのような作業をやっていたので、喜び勇んでyarn addしたところで、望み通りの結果が得られるようになりました。ただ、(もちろん有害になることではなさそうとはいえ)childrenの中身の一部で変化しないエレメントも外側にくくりだされていて、けっこう積極的に処理しているんだなと感じた次第でした。

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

ReactプロダクトにTypeScriptの導入を検討する

概要

社内プロダクトはReact×Reduxのプロダクトがほとんどなのですが、型定義にはFlowが導入されていました。
また、一部には型が定義されていないので、これから導入する場合もあります。
型宣言の統一できていなかったところから、統一のルールを図り、一部採用されていたFlowをやめてTypeScriptへ移行しようとしている最中です…!

そもそも型が必要な理由

これは調べたり、教わったりしながらまとめた型定義のメリットです。

  • 開発者がラクできる

詳しい理由は

  • VSCodeがpropsの値を補完してくれるようになる
  • VSCode上で変数名の上にマウスを乗せると、どんな型が定義されているのかが分かる
  • 型定義自体がドキュメントになってくれる
  • 型を入れなかった場合、型違いによるエラーはブラウザ上のエラーだけで判断しなければならない

デメリットは

  • コードの記述量が増える
  • 初学者はTypeScriptを勉強するイニシャルコストが掛かる

今まで型に触れてこなかった私の場合は、型の恩恵を受けたことがありませんでしたが、人気なのは分かっていました。
「人気」以外にTypeScriptを入れようという強い動機が知りたいと思い、ドキュメントや記事をいくつか読んでいくことにしました。

(参考になる資料を拝見しましたので共有まで)
非破壊TypeScript

Flow vs TypeScript

静的型チェックには公式にもあるように、FlowかTypeScriptの2択になるかと思います。
圧倒的に流行っているのはTypeScript、これから型定義するのにFlowを採用するのはなんか違和感…ですよね。
「流行っている」という単純な理由だけでなく、「◯◯◯という理由があるからTypeScriptの方が良い」「Flowは◯◯◯というメリットがあり、TypeScriptは◯◯◯というデメリットがあるけれど、採用するならTypeScriptだよね」と断言できる判断材料を調べることにしました。
(?型初心者なので間違いもあるかもしれません。ご容赦ください)

記述の違い

記述の違いを見てもらうのが、イメージが湧きやすいかと思います。
TypeScriptのサンプルコードはこちらが見やすいです。
TodoList簡易版@Typescript+React+Redux
Redux Example の TODO List を TypeScript で作成

Flowのサンプルコードはこちらが見やすいです。
Redux Todos Example
flowtypeでredux-thunkの型定義を使う

Reduxが絡んでるので、Redux公式サイトのチュートリアルにあるTodoアプリにFlow、TypeScript、それぞれ入れたサンプルコードを用意しました。
create-react-appで作ってますが、作成手順は他の優秀な記事を参考にしてください!

https://github.com/Hitomi-Nagano/flow_vs_typescript/pull/1/files#diff-8001576dd7ac440892e599590c14dcb5

上はプルリクの差分を見ていただきたかったのですが、全部js→ts、jsx→tsxに拡張子変えてしまったのでdiffが予想以上に多く見えてしまってます…!
変更前後で抜粋して表示すると、

7.png

上記のように// @flowを削除して、TypeScriptの記法に変えていきます。

8.png

Todoアプリは非同期処理がないので、Redux-thunk × TypeScriptをテーマにした素晴らしいQiita記事も拝見しましたので、ぜひご覧になってみて下さい〜

もう後押し…!

こちらの記事を参考にさせて頂きました。
Flow から TypeScript に移行しました

Flow
  • ライブラリなので導入は簡単
  • コントリビュータの数も多い 4.png 3.png
  • TypeScriptはコミュニティの規模が大きいですが、あまり気にならないかも(?)

でも…

  • バージョンアップデートがすごい 1.png

TypeScriptと比較すると分かりやすいかも
2.png

  • 型定義も不足している ?
TypeScript
  • jsx、jsとtsx、tsファイルが混在できる、ので段階的に導入できる Flowで問題なく運用していってるのであれば、後回しにしても良いかも(?) 機能拡大前の今のうちから入れるのは良いと思うけど
  • VSCodeの補完が効いている
  • Flowより記述が面倒な点もあるようだけど、一度開発環境整えて、後は経験積んでしまうのが良さそう…!

フロント以外の人が気にすること

もし運用中のプロダクトに導入することを検討するとしたら…?
TypeScriptについて知見のない方は以下のことが気になってきそうです。

  • 長期的に見てどっちがいいの?
  • イニシャルコストはどのくらい?(初心者の学習期間とか、プロダクト導入時とか)
  • 運用コストはどのくらい?

Flow vs TypeScript 参考記事

TypeScript × Reactのチート集、これがわかりやすかったです。

まとめ

TypeScriptについて知見が乏しかったのですが、自分で実装してみてVSCodeの補完が効くようになって、初めて恩恵を感じられました!
まだ”試しにやってみた”程度なのでTodoアプリで締め括りますが、ご意見ある方はむしろウェルカムです!!!

終わり

今Flow が入っているプロダクトへのアプローチが欠けていますが、また別記事で書ければな〜と思ってます。
また、Todoアプリは非同期処理がないので、アプローチとともに、Redux-thunk × TypeScript版もQiitaの記事を書こうと思います!

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

react-native-firebase analytics デバッグ手順

image.png

firebase analyticsにdebugモードが存在します。
いつも忘れてしまうのでまとめます。

デバッグモードの有効化

iOS

Xcodeのコマンドライン引数に以下を追加する。 チェックをONにしてビルドする。

-FIRDebugEnabled

無効にするときは以下を追加。

-FIRDebugDisabled

Android

# Debug On
adb shell setprop debug.firebase.analytics.app <package_name>

# Debug Off
adb shell setprop debug.firebase.analytics.app .none.


公式ドキュメントが正なので正確な情報は以下をご参照ください。
https://firebase.google.com/docs/analytics/debugview?hl=ja

image.png

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

Next.js 9で3分で1からTypeScriptのReactサーバーとGraphQLサーバを立てよう

概要

  • Next.js 9のAPI RouteにGraphQLのエンドポイントを生やします
  • Next.jsもGraphQLもTypescriptで書けます

やり方

1. 必要なパッケージをインストール

terminal
yarn add apollo-server-micro graphql micro next@latest react@latest react-dom@latest
yarn add -D typescript @types/react

2. テキトーにメインページを作る

pages/index.tsxを作り、テキトーにメインページを立ちあげる。拡張子をtsxにしておくと、Next.js 9は勝手にTypescriptのtsconfig.jsonを用意してくれる

速さ⚡️を求めるならば、tsconfig.jsonを書く前に、サーバーを立ち上げる。

テキトーなメインページの例?

pages/index.tsx
export default ()=>(
    <p>ほげ</p>
)

Reactのコンポーネントをexport defaultすればそれが配信される。画像などのファイルは/static配下に単に配置すれば配信される。

サーバー立ち上げ
terminal
yarn next
初回のターミナルのログの例
terminal
~/W/next9 graphql ❯❯❯ yarn next
yarn run v1.15.2
warning package.json: No license field
$ '/███████████/██████████/next9 graphql/node_modules/.bin/next'
[ wait ]  starting the development server ...
[ info ]  waiting on http://localhost:3000 ...
We detected TypeScript in your project and created a tsconfig.json file for you.

Your tsconfig.json has been populated with default values.

[ info ]  bundled successfully, waiting for typecheck results ...
[ ready ] compiled successfully (ready on http://localhost:3000)

http://localhost:3000
スクリーンショット 2019-07-09 13.55.19.png

※ Next.js 9からサーバーでプレレンダリングできていると、右下に⚡️マークがつくようになりました。

3. テキトーにGraphQLサーバーを作る

/pages/api配下にはAPIのエンドポイントを生やせる。GraphQLのモックサーバを立てよう。

/pages/api/index.ts
import { ApolloServer, gql } from 'apollo-server-micro';

// ここからGraphQLのモックの定義
const typeDefs = gql`
    type Query {
        hello: String
    }
`;

const resolvers = {
    Query: {
        hello: () => 'world',
    },
};

const apolloServer = new ApolloServer({ typeDefs, resolvers });

// ここから先はNext.jsが読みに行く領域
export default apolloServer.createHandler({path:"/api"});
export const config = {
    api: {
        bodyParser: false,
    },
};

サーバー再起動するまでもなく、APIが立ち上がる。

http://localhost:3000/api
スクリーンショット 2019-07-09 13.59.28.png

??嬉しい??

ここから、ApolloClientを入れるなり、モックじゃないGraphQLサーバーをこしらえるなりすると良い。

参考: Apollo Client + React 入門

終わり


ポイント

tsconfig書く前に、サーバー立ち上げてしまおう。

Next.js 9からは、tsxをNext.jsが見えるどこかにおけば、勝手に以下のtsconfig.jsonが用意されてしまう。tsc --initしたのが書き変わるのでさっさと立ち上げたいなら、nextを先にする方が早い。

短絡的に言えば、pages/index.tsx書けばオッケー。

tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": false,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve"
  },
  "exclude": [
    "node_modules"
  ],
  "include": [
    "next-env.d.ts",
    "**/*.ts",
    "**/*.tsx"
  ]
}

apollo-serverはmicro用のやつを使う。

pages/api配下で (req, res)を受け取る関数をexport defaultすれば、APIサーバが立つという寸法。

export default (req, res) => {
  res.setHeader('Content-Type', 'application/json')
  res.statusCode = 200
  res.end(JSON.stringify({ name: 'Nextjs' }))
}

デフォルトのres,req(ただし幾らかミドルウェアが入っている)をいじるより、Zeit▲のmicroでマイクロサービスを/pages/apiにもさもさ生やせば、賑やかになると思う。これはご機嫌。

参考:next.js/examples/api-routes-micro/

ということで、apollo-server-ナンチャラは、apollo-server-microを使うっぽいなあってのは、API Routeの見た目にわかった。しかし、GraphQLサーバを立たせるに当たって2点ハマりポイントがあった。

ハマり1. graphQLサーバのパスをちゃんと指定する。

apollo-serverはデフォルトでlocalhost:3000/graphqlにサーバーを立たせようとする。

一方で、Next.js 9はAPIを単純な設定ならばlocalhost:3000/api配下にしか生やせない。したがって、apollo-server-microcreateHandlerにオプションを指定する。

const apolloServer = new ApolloServer({ typeDefs, resolvers });

const handler = apolloServer.createHandler({path:"/api"});

このhandlerexport defaultすれば、graphQLサーバが立つもんだと思ったらそうはいかない。

ハマり2. export const config={option}ちゃんとする
export default handler;

したところでGraphQL Playgroundが動いているので、見た感じAPIが機能しているように思えるが、スキーマをダウンロードできない、クエリを投げられないで、まともに動いていない。

これは、Next.js 9が自動で設定しているbodyParserが原因らしい。数時間時間を潰してしまった。

Next.js 9のAPI routesは備え付けで少しのミドルウェア(cokkieやquery、bodyをreqに生やすことができるやつ)が入っており、その中で、bodyParserはデフォルトでonであり、reqをパースしてしまう。

しかし、API配下で、Next.js 9に設定を伝える方法があるのでこのようにすると、クエリも投げられるし、スキーマもダウンロードできるようになる。以下のconfigは決め打ちで。

export default apolloServer.createHandler({path:"/api"});

export const config = {
    api: {
        bodyParser: false,
    },
};

参考 next.js/examples/api-routes-graphql/

まとめ

  • 恐ろしく楽チンにNextのサーバーとGraphQLのサーバを立てられるようになった。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

agora.io クイックスタートガイド Electron用

概要

agora.ioにElectron用のSDKが公開されました。
コードはjavascriptで書きますが、利用するSDKのベースはNativeのものを利用できるので機能や安定性がすぐれています。

この記事では以下のサンプルのビルドを紹介します。
サンプル
フレームワークはReactを採用しています。

ビルド方法

1.上記サンプルプロジェクトをダウンロード
2.ファイルの展開
3.プロジェクトのルートフォルダへ移動
4.パッケージの追加

$ npm i

5.setting.jsにAPP IDを追記

setting.js
export const APP_ID = '****'

6.実行

$ npm run dev

以上で終わりです。非常に簡単ですね。

アプリの画面

ボイスチェンジャーやビデオの設定があります。
スクリーンショット 0001-07-09 12.34.59.png

その他にも画面共有やRTMPでの配信機能などが含まれています。
スクリーンショット 0001-07-09 12.36.07.png


agora.io日本語サイト


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

[React.js]Rails on Rails上でモダンなフロント環境構築

はじめに

React公式チュートリアルに挑戦するべく、Railsサーバ上でReactを動作させる環境を構築していこうと思います!

Rails5.1からwebpackerやnpm,yarnなどに対応したため、それらを利用してReactを使えるようにします。

目次

  • 1. yarnをインストールする
  • 2. Railsプロジェクトを作成する
  • 3. Gemfileの編集
  • 4. webpack,reactをインストールする
  • 5. 動作確認

前提環境

  • cloud9 (amazon linux)
  • Ruby 2.6
  • Rails 5.1
  • node 10.16

実践

1. yarnをインストールする

初めにyarnをインストールしておきます。

$ npm install -g yarn

2. Railsプロジェクトを作成する

おなじみrails newしていきます。
ついでにディレクトリも作成したプロジェクトに変更しておきます。

$ rails new webpack_test --skip-turbolinks && cd webpack_test

turbolinksはJavascriptにおいて不具合の原因になりかねないので使用しません。

3. Gemfileの編集

webpacker gemをインストールするため、作成したプロジェクトフォルダ内のGemfileを編集します

~省略~

gem "webpacker"

Gemfileを保存してからbundle installしてください。

4. webpack,reactをインストールする

webpackとreactをそれぞれインストールしていきます。

$ rails webpacker:install
$ rails webpacker:install:react

そして最後に
HTMLヘッダーを以下のように編集します
javascript_include_tagjavascript_pack_tag

javascriptを呼び出すときwebpackerのヘルパータグで<%=javascript_pack_tag'FILE_NAME'%>と記述します。

app/views/layouts/application.html.erb
<%= javascript_pack_tag 'application' %>

5. 実際に動作させてみよう!

正常にインストールできていれば
app/javascript/hello_react.jsxが作成されていると思います。
reactはjsx内で動作しているので、jsxファイルを呼び出すことでreactを動かします。

試しに、hello_react.jsxを表示させていこうと思います。

まずcontrollerとviewを作成しrouteを割り当てます。

rails g controller react_app index
config/routes.rb
Rails.application.routes.draw do
  get 'react_app/index'
end

作成したviewでjsxファイルを呼び出します。

view/react_app/index
<%=javascript_pack_tag 'hello_react'%>

rails サーバを起動して、正常に表示されるか確認します。

rails s

react_app/indexへ接続しHello React!と表示されていればReactの導入は完了です。

キャプチャ.PNG

6. Reactチュートリアルへの準備

公式Reactチュートリアル

まず、チュートリアル用に新しくjsxファイルを作っていきましょう。
app/javascript/pack/tutorial.jsxを作成しておきます。

tutorial.jsx内にreactをimportします。

tutorial.jsx
import React from "react"
import ReactDOM from "react-dom"
//ここから下の行にチュートリアルの内容を記述していく

実際にチュートリアルのスターターコードをtutorial.jsxに記述して動作を確かめてみます。

tutorial.jsx
import React from "react"
import ReactDOM from "react-dom"

class Square extends React.Component {
  render() {
    return (
      <button className="square">
        {/* TODO */}
      </button>
    );
  }
}

class Board extends React.Component {
  renderSquare(i) {
    return <Square />;
  }

  render() {
    const status = 'Next player: X';

    return (
      <div>
        <div className="status">{status}</div>
        <div className="board-row">
          {this.renderSquare(0)}
          {this.renderSquare(1)}
          {this.renderSquare(2)}
        </div>
        <div className="board-row">
          {this.renderSquare(3)}
          {this.renderSquare(4)}
          {this.renderSquare(5)}
        </div>
        <div className="board-row">
          {this.renderSquare(6)}
          {this.renderSquare(7)}
          {this.renderSquare(8)}
        </div>
      </div>
    );
  }
}

class Game extends React.Component {
  render() {
    return (
      <div className="game">
        <div className="game-board">
          <Board />
        </div>
        <div className="game-info">
          <div>{/* status */}</div>
          <ol>{/* TODO */}</ol>
        </div>
      </div>
    );
  }
}

// ========================================

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

rails sを実行し、react_app/indexにアクセスしてみます。

この画面になっていればreactは正常に動作しています。
キャプチャ.PNG

このままでは、デザインがおかしいのでスターターコードのcssを適応していきます。

app/assets/stylesheets/react_app.scss
body {
  font: 14px "Century Gothic", Futura, sans-serif;
  margin: 20px;
}

ol, ul {
  padding-left: 30px;
}

.board-row:after {
  clear: both;
  content: "";
  display: table;
}

.status {
  margin-bottom: 10px;
}

.square {
  background: #fff;
  border: 1px solid #999;
  float: left;
  font-size: 24px;
  font-weight: bold;
  line-height: 34px;
  height: 34px;
  margin-right: -1px;
  margin-top: -1px;
  padding: 0;
  text-align: center;
  width: 34px;
}

.square:focus {
  outline: none;
}

.kbd-navigation .square:focus {
  background: #ddd;
}

.game {
  display: flex;
  flex-direction: row;
}

.game-info {
  margin-left: 20px;
}

もう一度rails sを実行しreact_app/indexに接続すると
このような画面になっていればチュートリアルの準備は完了です。
キャプチャ.PNG

あとがき

記事を書く経験が初めてでしたが、思ったより大変でした...。
分かりにくい箇所、至らない箇所があれば修正します。

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