- 投稿日:2019-07-09T22:57:06+09:00
変わらない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の中身の一部で変化しないエレメントも外側にくくりだされていて、けっこう積極的に処理しているんだなと感じた次第でした。
- 投稿日:2019-07-09T16:11:08+09:00
ReactプロダクトにTypeScriptの導入を検討する
概要
社内プロダクトはReact×Reduxのプロダクトがほとんどなのですが、型定義にはFlowが導入されていました。
また、一部には型が定義されていないので、これから導入する場合もあります。
型宣言の統一できていなかったところから、統一のルールを図り、一部採用されていたFlowをやめてTypeScriptへ移行しようとしている最中です…!そもそも型が必要な理由
これは調べたり、教わったりしながらまとめた型定義のメリットです。
- 開発者がラクできる
詳しい理由は
- VSCodeがpropsの値を補完してくれるようになる
- VSCode上で変数名の上にマウスを乗せると、どんな型が定義されているのかが分かる
- 型定義自体がドキュメントになってくれる
- 型を入れなかった場合、型違いによるエラーはブラウザ上のエラーだけで判断しなければならない
デメリットは
- コードの記述量が増える
- 初学者はTypeScriptを勉強するイニシャルコストが掛かる
今まで型に触れてこなかった私の場合は、型の恩恵を受けたことがありませんでしたが、人気なのは分かっていました。
「人気」以外にTypeScriptを入れようという強い動機が知りたいと思い、ドキュメントや記事をいくつか読んでいくことにしました。(参考になる資料を拝見しましたので共有まで)
非破壊TypeScriptFlow 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で作ってますが、作成手順は他の優秀な記事を参考にしてください!上はプルリクの差分を見ていただきたかったのですが、全部js→ts、jsx→tsxに拡張子変えてしまったのでdiffが予想以上に多く見えてしまってます…!
変更前後で抜粋して表示すると、上記のように
// @flowを削除して、TypeScriptの記法に変えていきます。Todoアプリは非同期処理がないので、Redux-thunk × TypeScriptをテーマにした素晴らしいQiita記事も拝見しましたので、ぜひご覧になってみて下さい〜
もう後押し…!
こちらの記事を参考にさせて頂きました。
Flow から TypeScript に移行しましたFlow
でも…
- 型定義も不足している ?
TypeScript
- jsx、jsとtsx、tsファイルが混在できる、ので段階的に導入できる Flowで問題なく運用していってるのであれば、後回しにしても良いかも(?) 機能拡大前の今のうちから入れるのは良いと思うけど
- VSCodeの補完が効いている
- Flowより記述が面倒な点もあるようだけど、一度開発環境整えて、後は経験積んでしまうのが良さそう…!
フロント以外の人が気にすること
もし運用中のプロダクトに導入することを検討するとしたら…?
TypeScriptについて知見のない方は以下のことが気になってきそうです。
- 長期的に見てどっちがいいの?
- イニシャルコストはどのくらい?(初心者の学習期間とか、プロダクト導入時とか)
- 運用コストはどのくらい?
Flow vs TypeScript 参考記事
- Flow vs TypeScript in React — My two cents
- TypeScript vs Flow
- TypeScript vs Flow Comparison
- Why TypeScript is the best way to write Front-end in 2019
TypeScript × Reactのチート集、これがわかりやすかったです。
まとめ
TypeScriptについて知見が乏しかったのですが、自分で実装してみてVSCodeの補完が効くようになって、初めて恩恵を感じられました!
まだ”試しにやってみた”程度なのでTodoアプリで締め括りますが、ご意見ある方はむしろウェルカムです!!!終わり
今Flow が入っているプロダクトへのアプローチが欠けていますが、また別記事で書ければな〜と思ってます。
また、Todoアプリは非同期処理がないので、アプローチとともに、Redux-thunk × TypeScript版もQiitaの記事を書こうと思います!
- 投稿日:2019-07-09T15:20:05+09:00
react-native-firebase analytics デバッグ手順
firebase analyticsにdebugモードが存在します。
いつも忘れてしまうのでまとめます。デバッグモードの有効化
iOS
Xcodeのコマンドライン引数に以下を追加する。 チェックをONにしてビルドする。
-FIRDebugEnabled無効にするときは以下を追加。
-FIRDebugDisabledAndroid
# 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
- 投稿日:2019-07-09T14:41:58+09:00
Next.js 9で3分で1からTypeScriptのReactサーバーとGraphQLサーバを立てよう
概要
やり方
1. 必要なパッケージをインストール
terminalyarn add apollo-server-micro graphql micro next@latest react@latest react-dom@latest yarn add -D typescript @types/react2. テキトーにメインページを作る
pages/index.tsxを作り、テキトーにメインページを立ちあげる。拡張子をtsxにしておくと、Next.js 9は勝手にTypescriptのtsconfig.jsonを用意してくれる。速さ⚡️を求めるならば、
tsconfig.jsonを書く前に、サーバーを立ち上げる。テキトーなメインページの例?
pages/index.tsxexport default ()=>( <p>ほげ</p> )Reactのコンポーネントを
export defaultすればそれが配信される。画像などのファイルは/static配下に単に配置すれば配信される。サーバー立ち上げ
terminalyarn 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)※ Next.js 9からサーバーでプレレンダリングできていると、右下に⚡️マークがつくようになりました。
3. テキトーにGraphQLサーバーを作る
/pages/api配下にはAPIのエンドポイントを生やせる。GraphQLのモックサーバを立てよう。/pages/api/index.tsimport { 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が立ち上がる。
??嬉しい??
ここから、ApolloClientを入れるなり、モックじゃないGraphQLサーバーをこしらえるなりすると良い。
終わり
ポイント
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-microのcreateHandlerにオプションを指定する。const apolloServer = new ApolloServer({ typeDefs, resolvers }); const handler = apolloServer.createHandler({path:"/api"});この
handlerをexport 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のサーバを立てられるようになった。
- 投稿日:2019-07-09T12:46:35+09:00
agora.io クイックスタートガイド Electron用
概要
agora.ioにElectron用のSDKが公開されました。
コードはjavascriptで書きますが、利用するSDKのベースはNativeのものを利用できるので機能や安定性がすぐれています。この記事では以下のサンプルのビルドを紹介します。
サンプル
フレームワークはReactを採用しています。ビルド方法
1.上記サンプルプロジェクトをダウンロード
2.ファイルの展開
3.プロジェクトのルートフォルダへ移動
4.パッケージの追加$ npm i5.setting.jsにAPP IDを追記
setting.jsexport const APP_ID = '****' …6.実行
$ npm run dev以上で終わりです。非常に簡単ですね。
アプリの画面
その他にも画面共有やRTMPでの配信機能などが含まれています。
agora.io日本語サイト
- 投稿日:2019-07-09T12:39:50+09:00
[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 yarn2. Railsプロジェクトを作成する
おなじみrails newしていきます。
ついでにディレクトリも作成したプロジェクトに変更しておきます。$ rails new webpack_test --skip-turbolinks && cd webpack_testturbolinksは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_tag→javascript_pack_tagjavascriptを呼び出すとき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 indexconfig/routes.rbRails.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の導入は完了です。6. Reactチュートリアルへの準備
まず、チュートリアル用に新しくjsxファイルを作っていきましょう。
app/javascript/pack/にtutorial.jsxを作成しておきます。
tutorial.jsx内にreactをimportします。tutorial.jsximport React from "react" import ReactDOM from "react-dom" //ここから下の行にチュートリアルの内容を記述していく実際にチュートリアルのスターターコードを
tutorial.jsxに記述して動作を確かめてみます。tutorial.jsximport 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にアクセスしてみます。このままでは、デザインがおかしいのでスターターコードのcssを適応していきます。
app/assets/stylesheets/react_app.scssbody { 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に接続すると
このような画面になっていればチュートリアルの準備は完了です。
あとがき
記事を書く経験が初めてでしたが、思ったより大変でした...。
分かりにくい箇所、至らない箇所があれば修正します。














