- 投稿日:2019-12-05T23:28:56+09:00
技術的負債を作らないためのReact Hooks入門
React Advent Calendar 2019 - Qiita の 12/4 です。12/5も終わろうとしていますが、僕の中ではまだ12/4です…。ほんとすみません…。
さて、技術的負債は、常に注意深く設計しない限り、必ず積み重なっていくものです。ウェブフロントエンドを含めたGUI開発では、テストがかかれないことも多いため、技術的負債を作らないために、React Hooks入門記事を書いてみました。
もっと詳しく!とかここが分からない!とかがあればぜひコメントなりいただければ、追記できる気力がある限り追記していきたいと思います。
サンプルコードは https://github.com/erukiti/react-hooks-without-debt に置いています。
React Hooks の基本
React Hooksの考え方や個々のAPI仕様に関しては、公式ドキュメント を読むとわかりやすいと思います。
また、筆者が書いた技術同人誌 Effective React Hooks もあります。
数年前に書いたReact+Redux入門のコンポーネントはES2015+のclass機能を使って書かれていましたが、React Hooksでは関数だけでコンポーネントを書きます。
関数を使う利点は、公式ドキュメントに書いてありますが、シンプルなコードにできることです。
- 関数にすることでクラス型コンポーネントにまつわる複雑さから開放される
- ただし、ただの関数ではステートなどを持つことができない(以前はHoCなどのテクニックを使っていた)
- カスタムフックによりコンポーネント関数をシンプルに保つための関数分割が可能になる
といったところがポイントです。
この記事では、個々のAPI
useState
やuseEffect
については踏み込まないので、それは公式ドキュメントを読んでおくといいと思います。セットアップ
create-react-appというツールを使えば簡単です。
# yarn yarn create react-app <project名> --template typescript # npm npx create-react-app <project名> --template typescriptカスタムフック
技術的負債を作らないためのReact Hooksの観点で重要なポイントは、カスタムフックと、カスタムフックのテストにあります。React Hooksでは、公式が用意している Hooks 関数だけではなく、自前の Hooks 関数を作成でき、これをカスタムフックと呼びます。
実は、React Hooksを使っても、単に公式の Hooks 関数を使うだけだと、密結合の呪いはクラス型コンポーネントの頃と同じ位には降り掛かってしまいます。それを解決するための方法がカスタムフックなのです。
カスタムフックは
useHoge
のような、use
で始まる関数であり、コンポーネント関数と同じように、Hooks 関数を呼び出すことができます。custom-hook.tsimport { useState, useCallback } from 'react' export const useTextInput = ( init: string = '', ): [string, (e: any) => void] => { const [value, setValue] = useState(init) const handleChange = useCallback( (e: any) => { setValue(e.target.value) }, [setValue], ) return [value, handleChange] }
useTextInput
はテキスト入力をするカスタムフックです。やっていることはとても単純で、初期値を元にuseState
でvalue
とsetValue
を作成し、handleChange
という関数をuseCallback
で作成し、value
とhandleChange
のみを返すものです。App.tsximport React from 'react' import { useTextInput } from './custom-hook' const App: React.FC = () => { const [name, handleChangeName] = useTextInput() const [favorite, handleChangeFavorite] = useTextInput() return ( <div> 名前: <input value={name} onChange={handleChangeName} /> <br /> 好きなもの: <input value={favorite} onChange={handleChangeFavorite} /> </div> ) } export default App使い方は
<input value={value} onChange={handleChange} />
のようにinput
タグに渡すだけです。さて、このカスタムフックはどうすればテストできるでしょうか?
$ yarn add -D @testing-library/react-hooks react-test-renderercustom-hook.test.tsimport { renderHook, act } from '@testing-library/react-hooks' import { useTextInput } from './custom-hook' test('useTextInput', () => { const { result } = renderHook(() => useTextInput('hoge')) const [value, handleChange] = result.current expect(value).toBe('hoge') act(() => { handleChange({ target: { value: 'fuga' } }) }) expect(result.current[0]).toBe('fuga') })
@testing-library/react-hooks
に含まれるrenderHook
と、act
を使います。
renderHook(() => useTextInput())
のようにカスタムフックを呼び出す関数を引数として渡します。このコードではわかりやすいようにテキストの初期値としてhoge
を渡しています。renderHook
の戻り値の.result.current
にはカスタムフック関数の戻り値がそのまま入っているため、さらにvalue
を取り出して、hoge
であることを確認します。あとは、
handleChange
を直接呼び出すことでカスタムフック関数の、文字入力の処理を実行しています。testing-library/react
やreact-hooks
では、何かしらコンポーネントに変化をもたらすときにはact
のコールバックの中で行います。これによりReactのレンダリングを内部的に行っています。カスタムフックを含めたフック関数はすべてReactコンポーネントありきの仕組みなため、このような処理が必要です。
act
が完了すると、result.current[0]
は、新しいvalue
に置き換わっているため、fuga
という値に置き換わっています。
renderHook
を使うとカスタムフックのテストが可能act
コールバック内でReactコンポーネントに変化をもたらす処理を行うポイントはこの2点です。
これにより、少なくともカスタムフックのユニットテストは可能になります。今回書き換えた
App.tsx
では、useTextInput
の呼び出しと、input
タグの組み立てくらいしか行っていないため、これ以上のテストは、できるとすればE2Eテストか画像回帰テストくらいです。技術的負債との戦い方
技術的負債が生み出される背景は色々あります。組織論、人員不足などは大きな問題ですが、そういったものはいったんさておき、技術的側面だけで見ると、密結合や低凝集性という設計上の問題、テストが無いなどが主たる原因です。
- 密結合・低凝集性などといった設計上の誤り
- テストがない
密結合との戦いについては、SOLID原則に関して筆者が書いた別のブログを御覧ください。
- よくわかるSOLID原則1: S(単一責任の原則)|erukiti|note
- よくわかるSOLID原則2: O(オープン・クローズドの原則)|erukiti|note
- よくわかるSOLID原則3: L(リスコフの置換原則)|erukiti|note
- よくわかるSOLID原則4: I(インターフェース分離の原則)|erukiti|note
- よくわかるSOLID原則5: D(依存性逆転の原則)|erukiti|note
凝集性については今回は省略します。
テスト
技術的負債と戦うためにはテストが必須です。ウェブフロントエンドでも同様です。
密結合をするとテストがしづらくなります。フルスタックフレームワークは密結合になりやすい問題があり、ユニットテストがしづらいケースがとても多いです。クリーンアーキテクチャなどでは、こういった問題に対しては、なるべくフレームワークの決定を遅らせる、依存しすぎないということで、なるべく疎結合を保つべきだとしています。
- ロジックに対してはユニットテストを書く
- ロジック(特にビジネスロジック)でユニットテストを書きづらいのならばそれは設計に不備がある(多くの場合は、フレームワークなどに密結合してしまっている)
カスタムフックは基本的にはユニットテストしやすいものです。
ウェブフロントエンドや他GUIにおいては、コンポーネントを Humble Object Pattern というデザインパターンで、Presentation と View を分離しましょう。
- テストしやすいもの Presentation はユニットテストを書く
- テストしづらいもの View は、E2Eテストか画像回帰テストなどを書く。もしくは自動テストを諦める
先程の、カスタムフックへの分割と、カスタムフックのユニットテストは、まさにHumble Object Patternです。
まとめ
結局の所、この記事ではあまり複雑なことを主張するわけではなく、React Hooksではカスタムフックを使うことで Humble Object Pattern をやりやすく、技術的負債を貯めないための第一歩にふさわしいということが、主張したいことでした。
- React Hooksにはカスタムフックという仕組みがある
- カスタムフックはコンポーネントをテストしやすいものとしづらいもので分離するのに向いている
- Humble Object Pattern によりテストしやすいPresentationとしづらいViewに分離する
- Presentationはユニットテストをする
- Viewは、E2Eテストか画像回帰テストか、あるいは諦めるなどで対処する
サンプルコードは https://github.com/erukiti/react-hooks-without-debt に置いています。
- 投稿日:2019-12-05T23:06:46+09:00
htmlをReactコンポーネントにぶちこんでやるぜ〜〜!!
はじめに
いなたつアドカレの五日目の記事です。
今回はReactで生のhtmlを扱うための方法とその時の注意について少し、、、
ざっくりいうと
- dangerouslySetInnerHTMLを使おう
- XSS に気をつけよう
- markdownから変換して表示も可能だよ
dangerouslySetInnerHTMLを使う
<span dangerouslySetInnerHTML={{ __html: html}} />dangerouslySetInnerHTML属性に__html(あんだーばーあんだーばーへいちてぃーえむえる)に展開したいhtmlを設定する オブジェクト を渡すことで指定したhtmlをタグ内部に展開することができます。
dangerouslyやねん
XSSの危険がつきまとってくるんですよね。
XSSってのはクロスサイトスクリプティングといって、テキストボックスにhtmlを埋め込み、予期せぬ動作をさせようとすることです。
これの何がdangerouslyかというと
- テキストボックスにスクリプトを入力し、javascriptを実行させることで、クッキーなどを盗みなりすましができる
- 同様に、アプリケーションの機能を悪用されるかもしれない
クッキーでセッションIDなんかを保持しているとなりすましの温床になりかねないですね。。。。
dangerouslyって名前についてるのはこういうところからなので、まあ、あまり使わない方がいいですね。じゃあどーやって対策すんの
** サニタイズ **
markdownがうんぬんかんぬん
markdownを生のhtmlに変換してここにぶちこんでやるぜーしたらmarkdownエディタのプレビューっぽいことできるって話
次回reactとmarkedのお話を書きます。。。。
- 投稿日:2019-12-05T22:46:38+09:00
サーバーレス将棋 AI - WebSocket 編
Web ブラウザからクラウド上の将棋 AI を呼ぶアプリケーションを作りました。(画像クリックで開きます)
将棋 AI が 伝説の ▲52 銀 を発見する瞬間を、ブラウザで体験できます!
背景
三年前、サーバーレス将棋 AI ☖ という記事を書きましたが、あれからサーバーレスを取り巻く技術的な環境は大きく変わりました。
AWS Lambda の実行時間・メモリ上限は増え、API Gateway が WebSocket に対応 しました。また AWS Amplify の登場で、バックエンド (Lambda と種々のデータソース) とフロントエンドを一元的に、開発から本番デプロイまでほとんど全てのフェーズで具体的なインフラを意識せずに実現できるようになりました。
現在のサーバーレス技術で、あらためて将棋 AI を利用してどんなアプリケーションが作れるのか、実証のためにこのデモを作りました。
アーキテクチャ
ブラウザアプリケーション、API Gateway、AWS Lambda の 3 つのコンポーネントで構成されています。
AWS Lambda 上で将棋 AI を走らせます。2019 年現在最も強い AI のひとつであるやねうら王 (探索部) と illqha4 (評価関数) をデプロイしています。
API Gateway はブラウザと Lambda の間に立つ WebSocket サーバーとして振る舞います。クライアント (ブラウザ) からのリクエストに応じて Lambda を起動し、Lambda からのメッセージをクライアントに WebSocket で非同期送信します。実装
全てのソースコードは こちらのリポジトリ にまとまっています。
Serverless Framework (AWS Lambda + API Gateway)
本当は Amplify でやりたかったんですが、2019/12 現在 API Gateway Websocket は 非対応 の模様。
今回は Serverless Framework で実装しました。AWS Lambda と API Gateway の実装・定義とデプロイを cli で完結することができます。大きくこのような流れです。
- 将棋 AI を Lambda 用にビルド
- Lambda 関数の実装と API Gateway (Websocket イベント) の定義
- デプロイ
ビルドについては こちらの記事 (やねうら王を AWS Lambda で動かす) をご覧ください。
Lambda 関数では、API Gateway のリクエストを受けて将棋 AI プロセスを起動し、AI の標準出力を改行で分割し Websocket に送信しています。React & Amplify
フロントは React を使っています。UI コンポーネントは chakra を使いました。 Box を並べるだけでそれっぽくなります。デフォルトカラーテーマが良い感じです。
あと SFEN (将棋 AI のメッセージフォーマット) の parse が地味に大変で、いつも頑張って自前実装しているんですが、今回は PEG.js という Parser Generator を使ってみました。構文定義ファイルから parser を生成してくれるもので、コーナーケースに気をつけながら集中して自前実装するより 100 倍ラクでした。
Amplify は静的コンテンツのホスティング機能のみ利用しています。
create-react-app
で開発開始して、amplify publish
でいきなり SSL のデプロイ済み URL が降ってくるのは便利です。注意点
API Gateway と Lambda の組み合わせで WebSocket を利用する場合にいくつか注意点があります。
1. 双方向通信ではない
WebSocket を利用すればブラウザアプリケーションと Lambda プロセスが双方向通信できるような気がしていたのですが、API Gateway + Lambda の組み合わせを使う限りこれは難しいようです。
具体的には、Lambda からブラウザに対しては非同期にメッセージを push できる一方で、ブラウザから Lambda に対しては "Lambda 起動リクエスト" しか送ることができません。そのため、将棋 AI のように単一プロセスがインメモリで状態を持ち対話的に処理を行う CLI アプリケーションについては、工夫が必要です。最初のリクエストで全ての情報を渡して、Lambda から逐次レスポンスを受け取る形になります。2. WebSocket が到達順序を保証しない
保証してくれません。かなりズレます。将棋 AI のように最新の結果のみに興味がある場合、何らかの対応を行う必要があります。
今回はメッセージに Sequence ID を振り、クライアントサイドで受信メッセージの再ソートを行いました。まとめと今後の展望
サーバーレス関連技術すごいですね。今回作ったアプリケーションについても、一連のバックエンド機能を実装するのにひと昔前だったらどれくらい手間がかかっただろうと考えると、気が遠くなります。
また、WebSocket ✕ 将棋 AI の相性の良さを感じました。従来の Web API だと 30 秒後に結果のみがポンと返ってきます。WebSocket にすることでリアルタイムに思考過程を表示でき、ユーザーが受け取れる情報量が格段に増えました。
今後は Windows ユーザーの恵まれた将棋検討環境 (将棋所など) を Mac やスマホで実現するウェブアプリケーションを作りたいです。ずっと言ってますが。
- 投稿日:2019-12-05T22:10:05+09:00
Reactの式展開について
Reactでコンポーネントを作るに当たって、変数展開は欠かせないものですが、微妙に気になることがいくつかあります。
消えるもの、消えないもの
よく条件で表示するものを変えるときに、
{condition || <SomeComponent />}
や{condition && <SomeComponent />}
のように書くこともあるかと思いますが、条件を満たさない場合、左側がそのまま描画対象となります。そして、
true
やfalse
、null
、undefined
、空文字列ならもちろん何も描画されないのですが、truthyなものは基本的に描画対象となりますし、falsyなものでも0は「0」として描画されてしまいます。
? :
を使って条件判定の後で描画するものを明確にする、あるいは展開箇所で不等号や!
、!!
などを直接書いてtrue
かfalse
しか入らないようにする、といった注意は払ったほうがいいかもしれません。テキストノードが入らない
ふつうに以下のようなHTMLを書くと、
<button>
とテキスト
の間には改行があるので、スペースが入ります。<p> <button type="button">ボタン</button> テキスト </p>一方で、JSXの場合は改行の絡むスペースはすべて無視される(
</button> テキスト
のように、同一行に書いたときは無視されません)ので、<button>
とテキスト
がくっついてしまいます。もちろん、「CSSで隙間を開ける」という解決策もあるのですが、スペースとしてのテキストノードを書いたほうがいい場面もあります。
このような場合、式展開の形で書けばスペースが消えることはありません。
<p> <button type="button">ボタン</button> { ' ' } テキスト </p> <p> <button type="button">ボタン</button> { ' テキスト' } </p>スペースだけ独立して書いてもいいですし、スペースに続く文言まで文字列として含むのもありです。
- 投稿日:2019-12-05T21:41:05+09:00
React Web App #2 とりあえず動かしてみる
概要
React のチュートリアルをもとにとりあえず動くものを作ってみました。
アプリ
縦横に部屋が広がる様子を作るのが目的ですが、
いったん一次元の配列で部屋を作ってみます。
移動もただのボタンで行い、createも色をつけるだけです。https://codepen.io/shti-f/pen/Jjodroz?editors=0010
Architecture
Atomic Architectureを採用したので、
Atoms, Organisms, Templates, Pagesと分かれるはずなのですが、
現状でTemplatesはないです。Atomsとして、ボタンと場所表示用の要素。
Organismsとして、Roomを作っています。(今回のアプリではTemplatesにあたる可能性もあります)
PageとしてPageを作り、主ロジックは現在全てPageが持っています。
- 投稿日:2019-12-05T21:22:56+09:00
Firebase×Reactでプログラミングお題サイトをつくった話
Firebase×Reactでプログラミングお題サイトをつくった話
この記事は、ひとり開発 Advent Calendar 2019の13日目の記事になります。
プログラミングお題サイトの紹介
個人開発が趣味の人ならあるあるだと思いますが、なんとなく開発したいけど何を作ろうかな~でも特に思いつかないな~
なんて迷ったりすることありますよね
そんな迷える個人開発者やプログラミング初心者向けのプログラミングお題サイトFirebase×Reactで作ってみました!
プログラミングお題サイト
ソースコードはこちら
https://github.com/yakipudding/programming-odai特徴①自分に合ったお題を探せる!
プログラミングお題サイトでは、人気のお題や特定のタグのお題を探すことができます
気に入ったお題に対して「いいね」をしたり、「つくってみたれぽ」を投稿することができます!
特徴②お題を投稿できる!
Markdown記法でブログ記事のように書けるので、体裁を気にせず気楽に投稿することができます!
チュートリアルでやった良い題材を投稿したり、自分のアイデアを共有してみんな作ってみて!ということもできます。特徴③つくってみたを投稿できる!
お題に対して、C○○kpadの「つくれぽ」ならぬ「つくってみたれぽ」を投稿することができます
お題をつくったブログ記事やGitHubレポジトリを投稿することで記事を見てもらうきっかきになったり、初心者プログラマが参考にしたりすることができます!
作ってみた系や個人開発系の記事はQiitaだろうがブログだろうがスルーされやすい
全然いいねつかない
(気がする)ので、つくってみたれぽを公開して他の人に見てもらう機会を増やそう!というコンセプトもあったりします笑
プログラミングお題サイトを作ってみて
我ながらなかなか良いアイデアのWebアプリが作れたな~と、わりと気に入っています、、、が
なかなか苦労した点も多くありましたいいね機能、意外と奥が深い件
SNSっぽくいいねつけられるようにしよう!と思ったのですが、いざ実装しようとすると意外と大変でした。
「いいね」機能を実装するためには、「誰が何にいいねした」「どの記事に何いいねついているか」「自分がなんの記事にいいねしたか」などの情報を取得できるように、いいね情報をDBに登録する必要があります
- お題に「いいね」をしたとき
- いいねテーブルにユーザーID・お題IDのレコードを挿入
- お題の「いいね」を削除したとき
- いいねテーブルのユーザーID・お題IDのレコードを削除(または削除フラグ)
- お題一覧をみたとき
- お題ごとにログインユーザーが「いいねしているかどうか」をいいねテーブルとJOINして取得
たかだか「いいね」機能ですが、必要なDB処理はそこそこあるな、、という感じに。。。
さらにDBはFirebaseのRealtime Database※を使っていた関係でJOINができないため、手動JOIN(お題IDでループで回して取得)する必要があったりして…
RDBの偉大さを知ったのでした。。。DB設計に関してはお題に対していいねユーザーを紐付けるなど様々なやり方がありますが、いいねしたお題一覧も見たい(未実装)な~と考えたりしたのもあり、別テーブルとして保持することにしました
※FirebaseのDBはRealtime DatabaseとFirestoreがあり、機能としては後者のほうが良いです(クエリ機能が充実しているなど)
Firestoreを使わなかった理由は、課金単位が1日単位であり、かつそこそこシビアな上限だからです。こういうアドベントカレンダーで公開するようなサービスだと公開日にアクセスが集中してしまうと(しなかったら悲しい)上限に達してしまうため、ちょっと向いていないかもな…と避けました。ちなみにFirestoreもJOINはできません。。。タグ機能、なかなか実装がつらかった件
お題に対してタグ(複数可)をつけて検索できるといいよね!とかる~く思ったのですが、、意外とタグ機能は要件がエグかったです。。。
- タグの情報をどうやって保存するのか問題
- お題に対して複数登録できるタグの情報を保存しておく必要がある
- タグ項目を1つ用意しておき表示時に分割する?
- お題に対して登録したタグのテーブル(1-N関係)を用意する?
- タグで検索できるようにする必要がある
- このタグが付与してあるお題一覧を取得する、というクエリが必要
- タグのもたせ方によって検索がエグくなってしまう
という問題があったため、DB設計に関して工夫が必要でした。
ちなみにRealtime DatabaseはLike検索ができません結局、
- お題テーブルにタグ項目(1項目でスペース区切り保持)をもたせる
- お題投稿時、お題タグテーブルに対してタグID・お題IDのレコードを登録
- タグ検索時、お題タグテーブルからタグIDで抽出して検索
という形で無理やりなんとかしました。。
RDBではないので正規化はしません世の中のWebサービスすごいってなった
個人開発レベルやいいね機能とタグ機能をさくっと実装しようとしてもこんなに大変なのに、ユーザー数多いWebサービスって本当にすごいな…と思いました。
こういった「世の中のWebサービスでよくある機能」を個人開発で実装してみるのも、実装の難しさを肌で感じたりできるので楽しいですよ!RDBすごいってなった
タダより高いものはない精神でNoSQLのFirebeseのRealtime Databaseを使っていましたが、やはりJOINができなかったりLike検索ができない関係で、リッチな実装は限界があるなぁと感じました。
DBを無料で使えるという強力すぎるアドバンテージですが、実際の運用を考えるとかなり設計を工夫しないと難しいんだろうな~と思います。。普段はRDB(SQL Server)を使っているのですが、RDBが便利すぎて設計はあぐらをかいていたな~というか、楽をしていたんだな~と身にしみました。
RDBであってもデータの参照のされ方を意識して、JOINやWHEREのキーを意識したりインデックスを考えた設計にしないといけないな…と改めて思いました締め
というわけでプログラミングお題サイトの紹介でした!
いろいろ苦労もありますが、趣味の一つとして個人開発はやっぱり楽しいですね。今後もいろいろ作っていこうと思います。
- 投稿日:2019-12-05T21:03:24+09:00
reactive-react-reduxの紹介
はじめに
本記事では、ReactでReduxを使うためのライブラリを紹介します。このライブラリは、先日紹介したreact-trackedのRedux版とも言えます。
reactive-react-reduxとは
リポジトリはこちらです。
https://github.com/dai-shi/reactive-react-redux
Reduxが公式に提供しているReact向けライブラリは、react-reduxと呼ばれます。reactive-react-reduxは非公式ライブラリで、公式ライブラリの代わりに使えるものです。ただし、Hooks APIしか提供しません。
公式のReact ReduxのHooks APIとの差分は2点あります。
- useTrackedStateというhookを提供する
- stateを直接contextに入れる方式を採用する(storeではなく)
今回は前者について説明します。
そもそも課題はなにか?
実はこのライブラリを作ったのは、connectへの不満からでした。Reduxはもっとシンプルに使えるものであるはずと思い、mapStateToPropsを排除したAPIを提供したかったというのが動機です。
現在では、useSelectorというhookが公式ライブラリから提供されているので、その差分で説明したいと思います。
例として、storeのstateが次のような形をしているものを考えましょう。
const state = { user: { lastName: 'React', firstName: 'Hooks', age: 1, }, color: 'white', };このstateを使って、コンポーネントでfirstNameとlastNameを表示してみましょう。useSelectorを使った典型的な書き方は次のようになります。
const Component = () => { const firstName = useSelector(state => state.user.firstName); const lastName = useSelector(state => state.user.lastName); return ( <div> <div>First Name: {firstName}</div> <div>Last Name: {lastName}</div> </div> ); };connectに慣れている方は、useSelectorが複数あることに慣れないかもしれませんが、これがオススメされる書き方です。
仮にここで、
const { firstName, lastName } = useSelector(state => ({ firstName: state.user.firstName, lastName: state.user.lastName, }));のように書いてしまうと、動作はしますが、望まない形になります。望まない形とは、state.colorだけに変更があった場合でも、このuseSelectorはコンポーネントを再renderすることを指します。これが起こるのは、useSelectorに指定している関数が毎回新しいオブジェクトを生成するためです。
これを回避する(オススメはuseSelectorを分けることですが、それができない場合に)方法は、公式ライブラリでは2つあります。
- equalityFnを第二引数に指定する
- memoized selectorを作って使う
この辺りが、React Reduxが難しく感じる理由の一つだと感じています。
そもそも、selectorというのは大きいstateオブジェクトから必要なものを選択してくるというAPIとしてはとても分かりやすいものです。そこに、パフォーマンス向上(ここでは無駄なrenderを抑制すること)のために、selectorにreference equality(=参照透過性)の概念を持ち込むことが難しさの原因かと思います。
useTrackedStateを使うとどうなるか?
useTrackedStateを使うと上記のコードは、次のようにかけます。
const state = useTrackedState(); const { firstName, lastState } = state.user;もしくは、selectorを別で定義したとして、次のようにも書けます。
const selectUserNames = state => ({ firstName: state.user.firstName, lastName: state.user.lastName, }); const Component = () => { const { firstName, lastName } = selectUserNames(useTrackedState()); return ( <div> <div>First Name: {firstName}</div> <div>Last Name: {lastName}</div> </div> ); };このように特にreferential equalityを気にせずにselectorを書いたとしても、useTrackedStateにより、無駄なrenderを抑制することができます。
なぜそんなことができるのか?
ReduxメンテナーのMarkのブログ記事では、「Magic?」として紹介されています。reference equalityを意識してselectorを書いている人には、むしろこの挙動が予測不能なものに感じるのかもしれません。
useTrackedStateが動作する仕組みは、Proxyによるものです。
Proxyを使うと、オブジェクトへの操作を追跡(Track)できます。つまり、storeの大きなstateの中でどのオブジェクトプロパティにアクセスしたかを知ることができます。これを利用して、アクセスがあったプロパティに変更があった場合のみコンポーネントを再renderするようにuseTrackedStateが制御しています。
Proxyって遅いんじゃないの?
比較対象を何にするかですが、まず、人が正しくreferential equalityを考慮したselectorを書けるとは限らないということは伝えたいと思います。その場合は、機械がTrackする方が正確になります。もちろん無駄がなく、トータルで速いです。
仮に、完璧なselectorを人が書けたとして、Proxyにはオーバーヘッドがあるのは事実です。簡単な例でベンチマークをした結果を載せます。
ここで比較すべきは、reactive-react-reduxのuseTrackedStateと同じくuseSelectorのカラムです。このベンチマークではほとんど差がないことが分かるでしょう。他のベンチマーク評価もしましたが、極端な例では差が出るものの、実用に耐えうる範囲とみています。
Proxyを利用している他のプロジェクト
React系では、immerやMobXでProxyが使われています。また、Vue.jsでも使われているとのことです。
Redux Toolkitではimmerを採用していますし、今後Proxyを使ったライブラリは増えてくるかもしれません。
おわりに
reactive-react-reduxのuseTrackedStateについて紹介しました。興味を持ってくださった方は、ぜひ触ってみてください。ちなみに、react-trackedにも同じhookが用意されていますので、非Redux派の方はそちらをどうぞ。
今回は踏み込みませんでしたが、useTrackedStateにも限界がないわけではありません。例えば、次のようなuseSelectorの例については、useTrackedStateで同じ挙動を再現することはできません。
const isYoung = useSelector(state => state.user.age < 10);最後に、Redux系は、最近、Redux Toolkitをはじめ、ドキュメントの充実化など様々な改善が行われています。これから学び始める人には、良い環境になってきていると思います。
- 投稿日:2019-12-05T19:33:03+09:00
【React】Propsについて
Userコンポーネントにprops
Tarp
を渡す/src/App.jsimport React, {Component} from 'react'; const App = () => { return( <div> <User name={"mee"} /> </div> ) } const User =(props) => { return <div>hi i am {props.name}</div> } export default App;$ yarn run startリストレンダリング
次のソースコードは
/src/App.jsimport React, {Component} from 'react'; const App = () => { return( <div> <User name={"mee"} age={10}/> <User name={"mememe"} age={4}/> </div> ) } const User =(props) => { return <div>hi i am {props.name}, and {props.age}さいです</div> } export default App;mapを利用して記述することができる。
/src/App.jsimport React, {Component} from 'react'; const App = () => { const profiles = [ {name: "taro", age:10}, {name: "hanako", age: 5} ] return( <div> { profiles.map((profile) => { return <User name={profile.anme} age={profile.age}/> }) } </div> ) } const User =(props) => { return <div>hi i am {props.name}, and {props.age}さいです</div> } export default App;
- 投稿日:2019-12-05T17:51:11+09:00
? React Suite 4.0 release
The new semester is another new starting point. React Suite is welcoming the release of version 4.0. Since the design of the V4 version in March 2019, after more than six months of development and testing, discussions and disputes, I have finally completed all the plans.
In this harvest season, we have prepared a series of updates for everyone, are you ready?
1, migrate from Flow to TypeScript
First of all, thanks to Flow for supporting the entire V3 release, the component library can easily have static type checking. With the wider use of TypeScript and the problems that Flow has exposed, we have abandoned Flow in this release and refactored all the code with TypeScript. Make the code more readable and maintainable.
2, accessibility improvement
To support the new browser features, we abandoned IE9 in the previous version of V3. But we still hope that the Web application developed with React Suite will be used by as many people as possible and better. We try to reach more people in terms of accessibility.
2.1 Color contrast improvement
There are many people with low vision in the world, and the display used by these users is often uneven. The contrast between text and background becomes the most basic functional problem for users. As a thoughtful UI component library, how can you not take care of the user's eyes?
According to the requirements of the 《Web Content Accessibility Guidelines (WCAG) 》, the color of the text, the thickness of the font, we have improved the contrast, and adjusted the algorithm of the swatch, the purpose is to make your product more accessible.
2.2 Support dark mode
In the electronics around us, night mode is supported from the operating system to browsers, editors, and various readers. It is a high-contrast, or reverse-color display mode. If your users need to use your product for a long time, having a night mode can effectively alleviate eye strain and make it easier to read.
The Dark Mode theme has been added to the default theme, and provides a full customizable option. When developing, you only need to import the corresponding style file:
import 'rsuite/lib/styles/themes/dark/index.less';More on topic related settings can be referenced: custom theme
3、Added some components
The component is the smallest unit provided by React Suite. As Web applications become richer and more diverse, we will continue to offer a richer set of components.
3.1 Support for List
The List component is used very much on the mobile side, but in the mid- and back-end products, it has always been a component that is not well standardized. The required representations in different business scenarios will be different, so that we implement it in this version. List In addition to customizing the content of each item, we provide drag and drop sorting by default.
3.2 Support for Placeholder
In the front-end industry, everyone knows the word "skeleton screen". Its function is similar to that of Loader. It is a state displayed to the user before the application is not loaded, telling the user that the current data is being loaded. The advantage of the "skeleton screen" is to give the user a general structure of the page before the data has not been loaded, and enhance the sensory experience.
Placeholder is such a component that provides a rough structure of data. The general structure of the content area can be drawn by lines, rectangles, and circular outlines.
3.3 Support for Calendar
Calendar is a simple calendar panel that displays data for the calendar. Two usage scenarios are provided. One is to display a large calendar panel full of containers by default, which can display data for one month. The other is to provide a small, compact, small calendar panel that we often encounter in some systems' sidebars for data filtering.
3.4 Support Avatar and Badge
Support for Avatar components for displaying an avatar or trademark.
Support for Badge components for buttons, numbers next to icons, or status markers.
4、Breaking changes
We hope that each update will be most compatible with the historical version. But there are still some breaking changes, such as the use of new React features, or improvements to previously unreasonable designs.
4.1 Less than React 16.6 version is not supported
Some of React's new features are used in this release. For example, the new context API, which started to support the Class component static contextType property in React 16.6.0 #13728, uses this feature. So to use React Suite 4.0, you must upgrade react and react-dom to >=16.6.
4.2 Less compatibility change
In this release, support for the Dark theme has been made, and the introduction address of the
Less
file has been adjusted.3.x version
less
import 'rsuite/styles/less/index.less';
4.x version
```less
import 'rsuite/lib/styles/themes/default/index.less'// or
// import 'rsuite/lib/styles/index.less';
```The version of
Less
needs to be upgraded to the >=3.0 version.4.3 TreePicker and CheckTreePicker discard the expandAll attribute
The
TreePicker
component and theCheckTreePicker
component deprecated theexpandAll
property and added theexpandItemValues
property to expand the specified node.4.4 Adjusted the values of
Dropdown
,Whisper
, and allPicker
componentsplacement
propertiesThe
placement
attribute is the position that the configuration selector displays after it is opened. To make the parameters more readable, the values are adjusted as follows:type Placement4 = 'top' | 'bottom' | 'right' | 'left'; type Placement8 = | 'bottomStart' | 'bottomEnd' | 'topStart' | 'topEnd' | 'leftStart' | 'rightStart' | 'leftEnd' | 'rightEnd'; type PlacementAuto = | 'auto' | 'autoVerticalStart' | 'autoVerticalEnd' | 'autoHorizontalStart' | 'autoHorizontalEnd';Compatible with 3.x version
5、Bugfix and improvement
5.1 All Picker components support size
We have a very complete Picker series of components in the data entry component, which is often used in some data filtering columns, in addition to being used in forms. Considering that the Input and Button components have a size attribute that can be resized, the size attribute is also added to all Pickers to accommodate more scenarios.
5.2 Overflow protection for Whisper and Picker components
All Picker components and Whisper components are pop-up floating layers at a specified location, but sometimes because the size of the floating layer exceeds the extent of the container, some floating layers are not blocked. You can set a
preventOverfow
property at this time. The relative position of the floating layer display is adjusted according to the free space of the container, and the floating layer is displayed on the page as much as possible.5.3 FormControl component read-only and plain text
FormControl adds 2 props support:
readOnly
makes the form component read-only and cannot be edited.plaintext
lets the form components be displayed in plain text.When these two properties are set on the Form component, all the form components in the form are globally set. In many cases, we need to add a data detail page to the completed form. At this time, we need to add a new module and display the data. To improve code reusability, you can turn a form into a data detail panel by setting a plaintext property on the Form component.
5.4 DatePicker and DateRangePicker support display weeks
<DatePicker showWeekNumbers /> <DateRangePicker showWeekNumbers />If you need to view the number of weeks in your business in your business, you can set the
showWeekNumbers
attribute on the calendar, and the number of weeks in the current line will be displayed on the left side of the calendar.5.5
Form
combinationSchema
supports asynchronous checkAsynchronous verification is a basic requirement, and in this release Schema starts supporting Promise. Here are a few of the improvements to the form:
- Set the
checkAsync
attribute on<FormControl>
that requires asynchronous validation.- The validation rules for asynchronous validation add an object with a return value of Promise via the ʻaddRule
method of
schema`.- The check can be triggered manually by calling
checkAsync
andcheckForFieldAsync
of<Form>
.Model
In the example we need to asynchronously verify that an email address already exists on the server. When adding a rule to Modal, we return a Promise object via the addRule method.
function asyncCheckEmail(email) { return new Promise(resolve => { // Asynchronous processing logic // resolve(true); }); } const model = SchemaModel({ email: StringType() .isEmail('Please input the correct email address') .addRule((value, data) => { return asyncCheckEmail(value); }, 'Email address already exists') });Form
Set the declared model onForm
and set acheckAsync
property for the component that needs to be verified asynchronously.const formRef = React.createRef(); function render(){ return ( <Form model={model} ref={formRef}> <FormControl checkAsync name="email"/> </Form> ) }
Form
provides thecheck()
method by default, and thecheckAsync()
method is called if it is an asynchronous check.formRef.current.checkAsync().then(result => { console.log(result); });5.6 Alert and Notification support close method
Both
Alert
andNotification
support theclose
andcloseAll
methods, closing the last message and closing all messages, respectively. In some business situations, you need to turn off the warning message on the page after performing an operation. You can do the following:Alert.close(); Alert.closeAll(); Notification.close(); Notification.closeAll();5.7 FlexboxGrid supports responsive
The
Col
component in theGrid
layout is configurable for responsive layouts, but it doesn't have some features for Flex layouts. To make the two layouts fused, we can makeFlexboxGrid.Item
andCol
Combined, combined withFlexboxGrid
and with Flex layout features, and responsive configuration-related properties.<FlexboxGrid.Item componentClass={Col} md={6}> content </FlexboxGrid.Item>5.8 All Picker new open and close methods
In some cases, you need to open or close a
Picker
by performing an action. For example: a cascading operation, you want to quickly select after closing a Picker, the default is to put a nextPicker
. We provide aopen
andclose
method onPicker
:const pickerRef = React.createRef(); function render() { return <SelectPicker ref={pickerRef} />; } // open pickerRef.current.open(); // close pickerRef.current.close();5.9 Other fixes
- Fixed a Uploader upload file larger than 1GB display issue.
- Fixed compatibility issue with Input on IE browser display.
- Fixed an issue where InputPicker on the keyboard Delete key would clear the input worth.
- Fixed an issue where Dropdown set the
toggleComponentClass={Button}
background style error.- Fixed an issue where styles were missing when introduced on demand.
- Fixed an issue where DatePicker disabled days were inconsistent with disabled months.
- Fixed an issue where the scrollbar position was not updated after the Table data was updated.
- Fixed the Table property expandedRowKeys update value is not controlled.
- Fixed a callback parameter for the Table property onRowClick missing event.
- Fixed support for focus events by the Form component.
- Modified the default separator for Breadcrumb.
- Fixed an issue where the position of the handle was not updated after the Slider changed from hidden to display state.
6、At last
I hope that our growth will bring a better experience to more developers.If you like React Suite, you can show your support by either
- Starring this repo.
- Leaving a comment here if you are using RSUITE in your project
- Becoming a backer on OpenCollective
This project exists thanks to all the people who contribute.
- 投稿日:2019-12-05T16:31:51+09:00
GatsbyでFont Awesomeを使いたい
はじめまして、
のじみんといいますGatsbyほんと便利ですよね
今回はGatsbyでFontAwesomeを使用する方法について
インストールからフォントアイコンを表示するところまでを説明します実行環境とバージョン一覧
- Gatsby.js v2.18.4
- react-fontawesome v0.1.7 (Font Awesome 5)
ちなみに、Gatsbyは以下のスターターを使用してビルドしました↓
$ gatsby new my-blog https://github.com/gatsbyjs/gatsby-starter-blogまた、この記事では上記スターターでビルドしたGatsbyプロジェクトの
bio.js
に
記述していく程で話を進めていきますインストール
この記事ではFontAwesomeを使用するために以下の3つをインストールします
@fortawesome/react-fontawesome
@fortawesome/fontawesome-svg-core
@fortawesome/free-solid-svg-icons
npmの場合$ npm i --save @fortawesome/fontawesome-svg-core @fortawesome/free-solid-svg-icons @fortawesome/react-fontawesomeもしくは
yarnの場合$ yarn add @fortawesome/fontawesome-svg-core @fortawesome/free-solid-svg-icons @fortawesome/react-fontawesome
使用方法
インポート
以下のコードを
bio.js
に追記するbio.jsimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { library } from '@fortawesome/fontawesome-svg-core'フォントアイコンの表示
使用するフォントアイコンによって記述方法が若干異なるので分けて説明する
Twitterなどの有名企業のフォントアイコンを使用する場合
企業系のフォントアイコンを使用する場合は以下を上記に加えてインポートする
bio.jsimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { library } from '@fortawesome/fontawesome-svg-core' import { fab } from '@fortawesome/free-brands-svg-icons' // 追加使用するフォントアイコンを追加する
bio.jslibrary.add(fab)フォントアイコンを使用したい箇所に以下のコードを追加する
bio.js<FontAwesomeIcon icon={['fab', 'twitter']} />それ以外のフォントアイコンを使用する場合
それ以外のフォントアイコンを使用する場合、インポート時に
使用するフォントアイコン名を記述する必要があるbio.jsimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { library } from '@fortawesome/fontawesome-svg-core' import { faPen } from '@fortawesome/free-solid-svg-icons' //追加使用するフォントアイコンを追加する
bio.jslibrary.add(faPen)フォントアイコンを使用したい箇所に以下のコードを追加する
bio.js<FontAwesomeIcon icon={faPen} />実際に使ってみる
bio.jsimport { 割愛 } from '割愛' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { library } from '@fortawesome/fontawesome-svg-core' import { fab } from '@fortawesome/free-brands-svg-icons' const Bio = () => { const data = useStaticQuery(graphql`割愛`) const { author, social } = data.site.siteMetadata library.add(fab) // FontAwesomeのライブラリ読み込み return ( <div> <Image/> <p> <strong>{author}</strong> <a href={`https://twitter.com/${social.twitter}`}> <FontAwesomeIcon icon={['fab', 'twitter']} /> {/* ツイッターアイコン */} </a> <span>うぇぶとかかいはつ日記</span> </p> </div> )おまけ
無料のフォントアイコン一覧:Font Awesome
Gatsbyでフォントアイコンを使用する場合はフォントアイコン名を
キャメルケースで記述すれば使用できるはず(はず)例)
battery-full
(ケバブケース)
↓
batteryFull
(キャメルケース)ほんでは
参考
- 投稿日:2019-12-05T13:59:54+09:00
Githubを入稿システムとして使ってる
この記事はRecruit Engineers Advent Calendar 2019の7日目の記事です。
リクルートライフスタイルでHOT PEPPER Beauty cosme(以下HPBC)の開発を担当している@roronyaです。GatsbyJSを使ってGithubを「運営からのお知らせ」の入稿システムにするための設定やアプリの実装方針について紹介します。
HPBCには「運営からのお知らせ」という新機能やキャンペーンをユーザーに知らせる画面があります。
「運営からのお知らせ」に表示する文面は、その特性上ディレクターやマーケターが用意する場合が多いのですが、HPBCでは、「運営からのお知らせ」用の入稿システムを作らずに、Githubを入稿システムとして使ってもらっています。
最近のGithubは、Web上でファイルの追加や編集ができるたり、更にその変更をブランチを切ってPRを作るところまで簡単にできたりするので、Gitの知識が無くても使えるツールになってきています。Githubに原稿が来てしまえば、あとはCIでアプリで表示するためのAPIを叩いたりデプロイをしたりといった作業を任せることができます。エンジニアが何か作業をする必要がないので効率的です。
他にも以下のようなメリットがあります。
- Markdown Previewのついたエディタがデフォルトで備わっている
- 意識させずにバージョン管理を強制できる
- PRで文面のレビューがやりやすい
この記事ではGithubの機能を活かして入稿システムとして使うためのGatsbyJSの設定やAPIやアプリの実装方針について紹介します。また、サンプルコードは以下のリポジトリに置いておきます。
roronya/gatsby-notification入稿からアプリでの表示の流れ
以下のような工程でMarkdownをもとにお知らせページを生成しアプリで見れるようにしています。
- GithubにMarkdownをpushする
- pushにフックしてGatsbyJSで静的ページをbuild
- FirebaseHostingにデプロイ
- デプロイしたURLをAPIに登録する
- APIでURL一覧を返しアプリでWebViewで表示する
アプリでのお知らせの表示方法
アプリからお知らせを表示する方法は2通り考えられます。
- APIから文面をもらってアプリでレイアウトする
- Webページで作ってWebViewで表示する
1番のAPIから文面をもらう方法だと作れるお知らせ画面の自由度が減りそうだったので、今回はWebページで作ることにしました。
Markdownからページを生成する
静的ページジェネレータにはGatsbyJSを選びました。
GithubはMarkdownでファイルを編集するとプレビュー機能が使えるので、お知らせの文面もMarkdownで入稿できると、出来上がりが想像できて良さそうでした。GatsbyJSならMarkdownから静的ページを生成できます。
GatsbyJSの公式のドキュメント1を参考にMarkdownからページを生成できるようにしていきます。
大まかな流れは以下のようになります。
- GatsbyJSの導入
- Markdownを読み込むためのプラグインの設定
- ページ生成時の処理
初期化
適当なstarterを使って初期化します。今回はチュートリアル2と同様にgatsby-starter-hello-worldを使
いました。console$ gatsby new gatsby-tutorial https://github.com/gatsbyjs/gatsby-starter-hello-world
Markdownを読み込むためのプラグインの設定
GatsbyJSでMarkdownを読み込めるようにするためにプラグインの設定をします。必要なパッケージをインストールしてgatsby-config.jsに以下のように設定します。
console$ npm install --save gatsby-source-filesystem gatsby-transformer-remarkgatsby-config.jsmodule.exports = { plugins: [ { resolve: `gatsby-source-filesystem`, options: { name: `src`, path: `${__dirname}/src/`, }, }, `gatsby-transformer-remark`, ], }
gatsby-source-filesystem
がファイルを読み込むためのプラグインです。pathに指定したディレクトリからファイルを読み込みます。
gatsby-transformer-remark
は読み込んだファイルがMarkdownであるかを認識しHTMLに変換するプラグインです。加えて、このプラグインは、Markdownにfrontmatter形式で書いたメタデータを認識することも出来ます。メタデータは、URLとして表示するときのpathの設定をするために使います。Markdownをデータソースにしてページを書き出す
Markdownは
gatsby-transformer-remark
プラグインでHTMLに変換されますが、それはGraphQL上に存在しているのみで、具体的なページとしてはまだ書き出されていません。gatsby-node.js
はビルド時の処理を書けます。ここでMarkdownから作られたHTMLを取得し、後述するHTMLを埋め込むテンプレートを使ってページとして書き出します。gatsby-node.jsconst path = require(`path`) exports.createPages = async ({ actions, graphql, reporter }) => { const { createPage } = actions const template = path.resolve(`src/templates/notificationTemplate.js`) const result = await graphql(` { allMarkdownRemark { edges { node { frontmatter { path } } } } } `) // Handle errors if (result.errors) { reporter.panicOnBuild(`Error while running GraphQL query.`) return } result.data.allMarkdownRemark.edges.forEach(({ node }) => { createPage({ path: node.frontmatter.path, component: template, context: {}, // additional data can be passed via context }) }) }以下はHTMLを埋め込むテンプレートです。ここでHTMLにスタイルも当ててしまいます。HTMLを埋め込むdivにstyled-componentで適当に装飾してます。
/src/templates/notificationTemplate.jsimport React from "react" import { graphql } from "gatsby" import styled from 'styled-components' const Container = styled.div` body { margin: 0; } main { font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", YuGothic, "ヒラギノ角ゴ ProN W3", Hiragino Kaku Gothic ProN, Arial, "メイリオ", Meiryo, sans-serif; box-sizing: border-box; margin: 16px; } p { color: rgba(51,51,51,1); font-size: 13px; } h1 { padding-left: 4px; color: rgba(85,85,85,1); border-left: 4px solid rgba(85,85,85,1); font-size: 13px; } ` export default function Template({ data, // this prop will be injected by the GraphQL query below. }) { const { markdownRemark } = data // data.markdownRemark holds your post data const { html } = markdownRemark return <Container dangerouslySetInnerHTML={{ __html: html }} /> } export const pageQuery = graphql` query($path: String!) { markdownRemark(frontmatter: { path: { eq: $path } }) { html } } `APIへの登録
前述の通りアプリではWebViewでお知らせページを表示するので、APIにはURLを登録します。
URLの作り方
各MarkdownにFrontmatterでURLになるときのパスをメタデータとして記しておき、デプロイ時にデプロイ先のドメインと結合してURLにします。
APIに登録する
以下のようなデプロイスクリプトを書きます。全てのMarkdownを走査してメタデータを読んでAPIに必要なパラメータを作っています。HPBCではその他にも以下のようなメタデータをMarkdownに書いてAPIへ登録しています。
- title
- published_at
- 何時にお知らせを配信するか
- enabled
- APIからこのお知らせを返すか否か
- もし何か問題があったときにすぐに表示を変更できるようにしています
bin/deploy.jsconst fs = require("fs").promises const fm = require("front-matter") const axios = require("axios") const API_URL = process.env.API_URL const DEPLOY_BASE_URL = process.env.DEPLOY_BASE_URL const DIR = "./src/pages" const main = async () => { const files = await fs.readdir(DIR) const paths = files .filter(file => /.*\.md$/.test(file)) .map(file => `${DIR}/${file}`) const contents = await Promise.all( paths.map(async path => { const data = await fs.readFile(path, "utf8") return fm(data) }) ) const params = contents.map(content => ({ title: content.attributes.title, published_at: content.attributes.date, url: `${DEPLOY_BASE_URL}/${content.attributes.path}`, // デプロイされたときのURLを作る enabled: content.attributes.enabled, })) const response = await axios.post(API_URL, { contents: params }) } main() .then(console.log("done!")) .catch(err => { console.log(err) process.exit(1) })デプロイ
デプロイ先はFirebaseにしました。gatsby buildの結果をそのままdeployし、完了したら上記のスクリプトを叩いてAPIへ登録します。この一連の処理をpackage.jsonのscriptsに登録し、pushやmerge,tagのタイミングでdev,stg,prdの環境にそれぞれ適用しています。
package.json{ ... "scripts": { ... "deploy": "gatsby build && firebase deploy && node ./bin/deploy.js" } }たまにはリッチなコンテンツも作りたい
文章だけのお知らせ以外に、クリエイティブで訴えるお知らせを打ちたいということもあります。GatsbyJSはReactで自由度の高いコンテンツを作れるのでこういった要件にも答えることができます。
以下はユーザーに投稿するときの画像をどうやって撮影するかというコンテンツです。こういったコンテンツはMarkdownでは表現しづらいのでReactで作っています。
入稿方法は丁寧な説明書を作った
Githubは英語だし、変なボタンを触るとコードが壊れちゃうのでは!という不安があるらしかった。図つきの詳しいドキュメントを社内wikiに置いて参照してもらっています。
終わりに
GithubをGatsbyJSで入稿システムとして使うための設定の紹介をしました。入稿システムをいちから作るよりも早く作ることができました。CIが使えたり、GatsbyJSで作れるコンテンツの自由度が高いこともあり、クリエイティブで訴えるような施策にも対応できるので便利に使っています。
- 投稿日:2019-12-05T13:26:52+09:00
React で eject せずに Scoped SASS (.scss) を使う
概要
- scoped sass (ファイル内限定で適用されるスタイル) を使いたいでござる
- でも
npm run eject
はしたくないでござるcra-sass
を導入するとかんたんにできるでござる参考文献
実行環境
create-react-app
で作った react project
- 既存プロジェクトなのでversionわからん すまん
- TypeScript
サンプルコード (変更前)
node-sass
を入れてふつーにscssを使うとこうなる。Sample.tsx
Sample.tsximport * as React from "react"; import "./Sample.scss"; export const Sample: React.FC = () => { return ( <div className="outer"> OUTER <div className="inner">INNER</div> <ul> {["red", "blue", "green"].map((each, index) => ( <li className={each} key={index}> {each.toUpperCase()} </li> ))} </ul> </div> ); }; export default Sample;Sample.scss
Sample.scss.outer { &, * { display: flex; flex-direction: column; padding: 8px; border-left: 1px solid gray; } font-size: 1.2rem; .inner { font-weight: bold; } ul { li { &.red { color: red; } &.green { color: green; } &.blue { color: blue; } } } }ビルド結果(html)
<div class="outer"> OUTER <div class="inner">INNER</div> <ul> <li class="red">RED</li> <li class="blue">BLUE</li> <li class="green">GREEN</li> </ul> </div>実行結果
この実装の問題点
Sample.scss に記述したスタイルのscopeはグローバルである。
すなわち、Sample.tsx と同時にロードされるコンポーネントに、
同じclassName(例えば.outer)が割りあたっていると、互いに影響を受け合いバグの原因となる解決策
閉じたscopeを扱うことのできるsass loaderを導入する
導入手順
cra-sass を導入
npm install --save-dev cra-sass
cra-sass を実行
$(npm bin)/cra-sass
するとなんかいっぱいインストールしてプロジェクトが魔改造される
package.json@ devDependencies + "cra-sass": "0.0.5", @ dependencies + "node-sass-chokidar": "^1.4.0", + "npm-add-script": "^1.1.0", + "npm-run-all": "^4.1.5", @ scripts - "start": "react-scripts start", - "build": "react-scripts --max-old-space-size=2048 build", + "start": "npm-run-all -p watch-css start-js", + "build": "npm run build-css && react-scripts build", "test": "react-scripts test", - "eject": "react-scripts eject" + "eject": "react-scripts eject", + "build-css": "node-sass-chokidar src/ -o src/", + "watch-css": "npm run build-css && node-sass-chokidar src/ -o src/ --watch --recursive", + "start-js": "react-scripts start"
--max-old-space-size=2048
とか無くなってぶっ壊れてんじゃん!
ってことで無駄にぶっこわされたとこは直しておくpackage.json- "build": "react-scripts --max-old-space-size=2048 build", + "build": "npm run build-css && react-scripts --max-old-space-size=2048 build",サンプルコード(リファクタ後)
Sample.scss
Sample.module.scss
に改名するSample.tsx
- scssのimport
- classNameの割当てのしかた
だけを変更
Sample.tsximport * as React from "react"; import styles from "./Sample.module.scss"; export const Sample: React.FC = () => { return ( <div className={styles.outer}> OUTER <div className={styles.inner}>INNER</div> <ul> {["red", "blue", "green"].map((each, index) => ( <li className={styles[each]} key={index}> {each.toUpperCase()} </li> ))} </ul> </div> ); }; export default Sample;ビルド結果
<div class="Sample_outer__144wv"> OUTER <div class="Sample_inner__EiBfI">INNER</div> <ul> <li class="Sample_red__1ktYQ">RED</li> <li class="Sample_blue__32ZOZ">BLUE</li> <li class="Sample_green__2OrZU">GREEN</li> </ul> </div>css部分の抜粋.Sample_outer__144wv { font-size: 1.2rem; } .Sample_outer__144wv, .Sample_outer__144wv * { display: flex; flex-direction: column; padding: 8px; border-left: 1px solid gray; } .Sample_outer__144wv .Sample_inner__EiBfI { font-weight: bold; } .Sample_outer__144wv ul li.Sample_red__1ktYQ { color: red; } .Sample_outer__144wv ul li.Sample_green__2OrZU { color: green; } .Sample_outer__144wv ul li.Sample_blue__32ZOZ { color: blue; }その他やったこと
scriptsが壊されてないかチェックしよう
start, build, test が、 cra-sass によって破壊されている恐れがある
特にdefaultから変更している場合注意しよう.cssが.scssと同階層に出力されるようになってうっおとしい
- node-sass-chokidar のしわざくさい
- でもoutputしなくするオプションとかなさげ
- めんどいから、別階層に吐かせて、ignoreすることにした
package.json- "build-css": "node-sass-chokidar src/ -o src/", + "build-css": "node-sass-chokidar src/ -o built-css/", - "watch-css": "npm run build-css && node-sass-chokidar src/ -o src/ --watch --recursive", + "watch-css": "npm run build-css && node-sass-chokidar src/ -o built-css/ --watch --recursive",.gitignore+/built-css
node-sass
をすでに使っていた場合、不要になる
npm r node-sass
おしまい
これで快適な React x Scoped SASS 生活が始まる
- 投稿日:2019-12-05T09:57:05+09:00
CSSだってJavaScriptの値が欲しい!
インターン先でreact + typescript + scssのお仕事をしている @haduki1208 と申します。
最近reactよりscssを多く書いてる気がします。割と楽しいです。TL;DR
- CSS変数をインラインスタイルで書く
- var()で読み込む
CSSでJavaScriptの値を取得する
趣味で「任意の大きさ・色・向きを指定できる矢印アイコン
」を作っていた時に
「CSSでJavaScriptの値を取得できないのか?」
と思ったのでやってみました。
cssにattr()という関数がありますが、content属性でしか動作しないようです。
今回はheight, width, background-color, rotateに任意の値を使いたいのですがダメです。微妙な仕様ですね。環境
- typescript + react + scss および typescript + react + styled-components
- chromeで動作確認
- 動いたコードをcodepenに移植(codepenを使ってみたかった
)
ソースコード
See the Pen Arrow01 react + ts + scss by haduki1208 (@haduki1208) on CodePen.
最初に作った矢印アイコンのソースコードです。
このコードの弱点は以下になります。
- size, color, rotateの1つでも違う値を使いたい場合、新たにclassnameを作成しなければならない
- tsxとscssの両ファイルに変更を加える必要がある
- mixinを使っているため、トランスパイル後のcssの容量が大きくなる
1番、2番は面倒くさいです。
これらを全て解消してみます。変更後のソースコード
See the Pen Arrow02 react + ts + scss by haduki1208 (@haduki1208) on CodePen.
CSS カスタムプロパティ (変数)を使いました。
ポイントは以下になります。
- style属性に指定したオブジェクトは、インラインスタイルに変換される
- インラインスタイルで記述されているため、CSS変数が他の要素に影響しない
- typescript環境の場合、React.CSSPropertie型以外のオブジェクトを代入するため「as any」する必要がある
これでscssを編集せず色々なアイコンを作ることができます!
おまけ styled-componentsに置き換えたソースコード
こんなことするなら、最初からstyled-componentsにすれば良いじゃないと思った人もいらっしゃるでしょう。
僕は今までstyled-componentsを使ったことがなかったので、勉強のため置き換えをしてみました。See the Pen Arrow03 react + ts + styled by haduki1208 (@haduki1208) on CodePen.
なんて素晴らしいライブラリなのでしょう。
scss、インラインスタイル、as any 全て消え去りました。
(ついでにwebpack.config.jsからstyle-loader, css-loader, sass-loader, postcss-loaderも消え去りました)styled-componentsに惚れてしまいそうです。
感想
react + scssで開発をしているプロジェクトでJavaScripの変数を取得したくなった時はこの方法で解決できそうです。
既にscssで開発しているプロジェクトでは、styled-componentsに移行するにも時間がかかってしまうので、もしcssからjavascriptの値を使いたくなったら、ご検討ください。
- 投稿日:2019-12-05T09:02:38+09:00
フロントエンドマスターへの道 その1 React Hooksを使ったQiitaの一覧、検索アプリ
せっかくなので作ってみようと思う。今回は 1 の Build a movie search app using React (with hooks) を作る。ただそのままだとただのコピペになってしまうので、今回取得するのは movie の取得ではなく Qiita の記事一覧にします。
どのフレームワークも何年か前にはさわっていたけど、最新の情報はなんとなく見たことある程度の知識しかありませんので詳しい解説をするものではありませんのでご注意ください。誤った理解のご指摘などがあれば大変助かります!
完成品はこちら(キャプチャの左はじがすこし切れた……)
CSS は基本的には今後も雑にしか作らずに、あまり本質的ではない Lint とかフォーマットの設定とかはデフォルトで入っていないものについては何もしない予定。
install
参考サイトのように
npx create-react-app hooked
でインストールしてもいいんだろうけど、大体の人は TS で書きたいと思うので、インストール時にはnpx create-react-app hooked --typescript
としなければいけません。自分は普通に忘れたので今回は普通の JS で書きました。hook
useEffect
とuseState
とuseCallback
というのは関数名だけは知っていた。useEffect については
React のライフサイクルに馴染みがある場合は、useEffect フックを componentDidMount と componentDidUpdate と componentWillUnmount がまとまったものだと考えることができます。
昔の知識のおかげか上記解説のヒントにあったこの説明が一番分かりやすくて、こういうある特定のタイミングで実行したい処理があった場合に
上記の hook から探して適切なものを使う、ということなのだろうかと理解した。
useEffect(() => { (async () => { const params = new URLSearchParams() params.set('page', 1) params.set('per_page', perPage) try { const response = await fetch(`https://qiita.com/api/v2/items?${params.toString()}`, { headers: { 'Authorization': `Bearer ${API_KEY}` } }) setArticles(await response.json()) } catch (err) { setErrorMessage(err) } setLoading(false) })() })実際に
useEffect
を使ったコードはこうなった。async/await に書き換えたんだけど、戻りがPromise<T>
になっているとまずいようでuseEffect(async() => {こうすることはできない。そのため即時実行関数を使うしかないのかなと思いこうしておいた。多少ググってもみたのですが、似たような感じのコードしかなかったのでこうするしかなさそう。
dotenv
たぶん一番苦労した。
最初に答えを書いておくと、
create-react-app
には最初から dotenv が含まれているため、開発環境では.env.development.local
にREACT_APP_
から始まる値で設定しないといけない。ぐぐれば結構でてくるし、当然ドキュメントにも書いてある。
yarn add dotenv
とかやってしまってハマった。感想
流石に1とあって簡単。後半きつそうなので不安しかない
- 投稿日:2019-12-05T09:02:38+09:00
フロントエンドマスターへの道 その1
せっかくなので作ってみようと思う。今回は 1 の Build a movie search app using React (with hooks) を作る。ただそのままだとただのコピペになってしまうので、今回取得するのは movie の取得ではなく Qiita の記事一覧にします。
どのフレームワークも何年か前にはさわっていたけど、最新の情報はなんとなく見たことある程度の知識しかありませんので詳しい解説をするものではありませんのでご注意ください。誤った理解のご指摘などがあれば大変助かります!
完成品はこちら(キャプチャの左はじがすこし切れた……)
CSS は基本的には今後も雑にしか作らずに、あまり本質的ではない Lint とかフォーマットの設定とかはデフォルトで入っていないものについては何もしない予定。
install
参考サイトのように
npx create-react-app hooked
でインストールしてもいいんだろうけど、大体の人は TS で書きたいと思うので、インストール時にはnpx create-react-app hooked --typescript
としなければいけません。自分は普通に忘れたので今回は普通の JS で書きました。hook
useEffect
とuseState
とuseCallback
というのは関数名だけは知っていた。useEffect については
React のライフサイクルに馴染みがある場合は、useEffect フックを componentDidMount と componentDidUpdate と componentWillUnmount がまとまったものだと考えることができます。
昔の知識のおかげか上記解説のヒントにあったこの説明が一番分かりやすくて、こういうある特定のタイミングで実行したい処理があった場合に
上記の hook から探して適切なものを使う、ということなのだろうかと理解した。
useEffect(() => { (async () => { const params = new URLSearchParams() params.set('page', 1) params.set('per_page', perPage) try { const response = await fetch(`https://qiita.com/api/v2/items?${params.toString()}`, { headers: { 'Authorization': `Bearer ${API_KEY}` } }) setArticles(await response.json()) } catch (err) { setErrorMessage(err) } setLoading(false) })() })実際に
useEffect
を使ったコードはこうなった。async/await に書き換えたんだけど、戻りがPromise<T>
になっているとまずいようでuseEffect(async() => {こうすることはできない。そのため即時実行関数を使うしかないのかなと思いこうしておいた。多少ググってもみたのですが、似たような感じのコードしかなかったのでこうするしかなさそう。
dotenv
たぶん一番苦労した。
最初に答えを書いておくと、
create-react-app
には最初から dotenv が含まれているため、開発環境では.env.development.local
にREACT_APP_
から始まる値で設定しないといけない。ぐぐれば結構でてくるし、当然ドキュメントにも書いてある。
yarn add dotenv
とかやってしまってハマった。感想
流石に1とあって簡単。後半きつそうなので不安しかない
- 投稿日:2019-12-05T08:32:35+09:00
Awesome React - Reactのオススメ記事・ライブラリ・ツール一覧 -
Awesome React
- この記事は次の日本語訳です(Reactの部分のみ抜粋)
公式
コミュニティ
オンラインでReactのコードを試せるサービス
チュートリアル
Reactのチュートリアル
- React Official Tutorial - 公式
- Using React in Visual Studio Code - ReactをVSCodeで使う
- Scrimba - Learn React for free interactively - ScrimbaのReactコース
- FreeCodeCamp React Challenges - FreeCodeCampのReactコース
- React Cheatsheet - チートシート
- React Patterns - Reactのコンポーネントのパターン集
- Setup Flow with React - ReactでFlowを使うセットアップ方法
React Hooksのチュートリアル
- React Hooks - 公式
- Replacing Redux with React Hooks and Context - ReduxをReact HooksとContextで置き換える
- React Hooks cheat sheet: Unlock solutions to common problems - React Hooksチートシート
- How to fetch data with React Hooks? - React Hooksで fetch APIを使うには?
- Easy to understand React Hook recipes - React Hooksのレシピ集
- Awesome React Hooks
React & TypeScript
パフォーマンス
- React Optimizing Performance - パフォーマンスの最適化
- Introducing the React Profiler - プロファイラーの紹介
- Optimizing React: Virtual DOM explained - 仮装DOMの説明
- A Definitive Guide to Optimize Major Performance issues in React - パフォーマンスの問題を最適化ガイド
- Twitter Lite and High Performance React Progressive Web Apps at Scale - Twitter Liteを例にした高パフォーマンスなPWAへの取り組み
- Using the React DevTools Profiler to Diagnose React App Performance Issues - React DevTools Profilerを使用してReactアプリのパフォーマンスの問題を診断する
- Top 5 Practices to Boost React Performance
- React is Slow, React is Fast: Optimizing react Apps in Practice - Reactアプリを最適化の実践
- Rendering large lists with react-window - react-windowで大量のリストを描画する
React内部の実装ついて
- Reconciliation - Reactの差分を検知するアルゴリズムについて
- React Fiber Architecture - Reactのコアアルゴリズムについて
- Build your own React - 独自のReactを構築するためのDIYガイド
- Inside Fiber: In-depth overview of the new reconciliation algorithm in React - Reactの新しい差分検知アルゴリズムの概要
ReactについてのQ&A
React Tools
React 開発ツール
- create-react-app - 1つのコマンドで最新のWebアプリをセットアップする
- react-starter-kit - webアプリ用テンプレート
- react-devtools - ChromeおよびFirefox開発ツールでのReactコンポーネント階層の検査
- react-hot-loader - Reactコンポーネントをリアルタイムで調整する
- react-loadable - promiseでコンポーネントを読み込むための高階層コンポーネント
- loadable-components - Reactコード分割を簡単にする、bundleサイズを縮小する
- reactotron - ReactおよびReact Nativeプロジェクトを検査するためのデスクトップアプリ
- storybook - UIコンポーネントの開発とテスト
- react-styleguidist - スタイルガイド付きのReactコンポーネント開発環境
- react-cosmos - 再利用可能なReactコンポーネントを作成するための開発ツール
- eslint-plugin-react - ESLintの特定のlintルールのプラグイン
- eslint-plugin-jsx-a11y - JSX要素のa11yルールの静的ASTチェッカー
- react-axe - Reactアプリケーションのアクセシビリティ監査
React フレームワーク
React スタイル
- styled-components - コンポーネントのスタイルに実際のCSSコードを記述できるようにするライブラリ
- emotion - JavaScriptを使用してCSSスタイルを記述するために設計されたライブラリ
- radium - Reactのインラインスタイルを管理するツールのセット
- jss - JavaScriptでスタイルシートを生成するためのライブラリ
React ルーティング
- react-router - Reactの宣言型ルーティング
- navi - Reactの宣言的な非同期ルーティング
- curi - 単一ページアプリケーション用のJavaScriptルーター
React UIコンポーネントライブラリ
- material-ui - Web開発を迅速かつ簡単にするためのコンポーネント
- ant-design - エンタープライズクラスのUIデザイン言語とReact UIライブラリ
- blueprint - Web用のReactベースのUIツールキット
- office-ui-fabric-react - Microsoft Webエクスペリエンスを構築するためのReactコンポーネント
- react-bootstrap - Reactで構築されたbootstrapコンポーネント
- reactstrap - Bootstrap 4のステートレスReactコンポーネント
- semantic-ui-react - Semantic-UIのReactコンポーネント
- react-fontawesome - Font Awesome 5 のReactコンポーネント
- Reakit - Reactのアクセス可能、構成可能、カスタマイズ可能なコンポーネント
- rsuite - エンタープライズシステム製品用の一連のReactコンポーネントライブラリ
- atlaskit - Atlassianデザインガイドラインに従って構築されたAtlassianの公式UIライブラリ
Reactの素晴らしいコンポーネント
- Awesome React Components list - 本当に素晴らしいReactコンポーネントとライブラリ
- react-select - Reactの選択コンポーネント
- react-dnd - Reactのドラッグアンドドロップ
- react-grid-layout - レスポンシブブレークポイントを備えたドラッグ可能でサイズ変更可能なグリッドレイアウト
- react-table - React向けの軽量で高速で拡張可能なデータグリッド
- react-data-grid - Reactで構築されたExcelのようなグリッドコンポーネント
- react-draggable - ドラッグ可能なReactコンポーネント
- react-resizable-and-movable - Reactのサイズ変更およびドラッグ可能なコンポーネント
- react-resizable - ハンドルでサイズ変更可能な単純なReactコンポーネント
- react-resizable-box - Reactのサイズ変更可能なコンポーネント
- react-sortable-pane - React用のソートおよびサイズ変更可能なペインコンポーネント
- react-dates - ウェブ向けの簡単に国際化可能でモバイル対応の日付選択ライブラリ
- react-big-calendar - カレンダーコンポーネント
- react-datepicker - Reactの日付選択ライブラリ
- react-list - 多用途の無限スクロールReactコンポーネント
- react-intl - Reactアプリの国際化
- react-i18next - Reactの国際化を正しく行うライブラリ
- react-aria-modal - 完全にアクセス可能なReactモーダル
- react-hotkeys - Reactの宣言的なホットキーとフォーカスエリア管理
- react-keydown - Reactコンポーネント用の軽量キーダウンラッパー
- react-joyride - アプリのガイドを作成するライブラリ
- react-virtualized - 大きなリストと表形式のデータを効率的にレンダリングするためのReactコンポーネント
- react-window - 大きなリストと表形式のデータを効率的にレンダリングするためのReactコンポーネント
- react-text-mask - React用Inputマスク
- react-loading-skeleton - アプリに自動的に適応するスケルトン画面を作成するライブラリ
- react-spinkit - 読み込み表示のCSSアニメーションのReactライブラリ
- rheostat - Reactで構築されたアクセス可能なスライダーコンポーネント
- qrcode.react - Reactで使用するQRコードのコンポーネント
Reactコマンドラインツール
- ink - React用のインタラクティブなコマンドラインアプリ
- react-blessed - ターミナルインターフェイスライブラリのReactレンダラー
Reactテストツール
- jest - JavaScriptテストフレームワーク
- enzyme - React用のJavaScriptテストユーティリティ
- react-testing-library - シンプルで完全なReact DOMテストユーティリティ
- react-hooks-testing-library - 優れたテストプラクティスを促進するReact Hooksテストユーティリティ
- majestic - JestのためのGUI
React Libraries
- react-border-wrapper - Reactのdiv境界に沿って要素を配置するためのラッパー
- react-magic - ReactでプレーンなHTMLにAJAXを使用できるようにするライブラリ
- react-toolbox - Googleのマテリアルデザイン仕様を実装する一連のReactコンポーネント
- tcomb-react - Reactコンポーネントのすべてのpropsをチェックできるライブラリ
- react-responsive - レスポンシブデザインに対応するメディアクエリ
- react-cursor - Reactで使用するためのFunctional Stateの管理の抽象化
- Omniscient.js - 不変データの高速トップダウンレンダリングのためのReactコンポーネントの抽象化
- Touchstonejs - 美しいハイブリッドモバイルアプリを開発するためのReact.jsを搭載したUIフレームワーク。
- Elemental - React.js WebサイトおよびアプリのUIツールキット
- StateTrooper - CSPでReactアプリケーションの状態を一元管理
- Preact - ReactのモダンなAPIを使用できる高速3kbのReactの代替ライブラリ
- riotjs - Reactのような3.5KBのユーザーインターフェイスライブラリ
- Maple.js - Webコンポーネントの概念をReactにもたらす
- react-i13n - Reactアプリケーションを計装するための、高性能でスケーラブルでプラグ可能なアプローチ
- react-icons - 人気のあるアイコンパックのsvgアイコン
- Keo - Reactコンポーネントを作成するためのより機能的なDekuアプローチのためのプレーン関数
- Bit - アプリケーション間でリアクションおよびその他のWebコンポーネントを管理および使用するための仮想リポジトリ
- AtlasKit - AtlassianのReact UIライブラリ
- ReactiveSearch - ElasticsearchのためのUIコンポーネントライブラリ
- Slate - リッチテキストエディターを構築するための完全にカスタマイズ可能なフレームワーク
- react-json-schema - JSON定義を公開するReactコンポーネントにマッピングして、JSONからReact要素を構築する
- compose-state - Reactで複数のsetStateまたはgetDerivedStateFromPropsアップデーターを作成する
- PrimeReact - Reactの最も完全なUIフレームワーク
- react-lodash - ReactコンポーネントとしてのLodash
- react-helmet - Reactのドキュメントヘッドマネージャー
- Stator - Reactの組み込みサポートを備えたシンプルでプレーンなJavaScript状態管理
- ClearX - 学習曲線がゼロでReact向けの高速で簡単な状態管理
- react-snap - SPAのためのゼロ構成フレームワークに依存しない静的事前レンダリング
- Draft.js - テキストエディターを構築するためのReactフレームワーク
- refract - リアクティブプログラミングのパワーを制御して、コンポーネントを満たす
- react-desktop - Reactで構築されたOS XおよびWindows UIコンポーネント
- Reapop - React&Redux通知システム
- react-extras - Reactを使用するための便利なコンポーネントとユーティリティ
- react-instantsearch - AlgoliaによるReactおよびReact Nativeアプリケーションの超高速検索
- uppy - Webブラウザー用の次のオープンソースファイルアップローダー
- react-motion - アニメーションの問題を解決するバネ
- react-esi - ReactおよびNext.jsの非常に高速なサーバー側レンダリング
Reactインテグレーション
- React Rails - ReactをRailsと使うための柔軟なツール
- ReactJS.NET - ReactコンポーネントのJSXコンパイルおよびサーバー側レンダリング用の.NETライブラリ
- React ASP.NET Boilerplate - ASP.NET Coreを使用して同じReactアプリケーションを構築するためのテンプレート
- React Bootstrap Components Playground - react-bootstrapの型チェック
- om - ReactのClojureScript UIフレームワークとクライアント/サーバーアーキテクチャ
- quiescent - React上の軽量ClojureScript
- Reagent - React.jsへの最小限のClojureScriptインターフェース
- react-haskell - HaskellのReactバインディング
- Express React views
- Express Coffee-React views - サーバー上でCofee-Reactをレンダリングする
- React Page Middleware
- ngReact - AngularのReactコンポーネント
- React Laravel
- coffee-react-transform - CoffeescriptのReact JSXサポートを提供
- sprockets-coffee-react - CJSXのスプロケットプリプロセッサ
- react-kup - coffeescriptのjsxに代わるシンプルで非侵入的な代替手段
- turbo-react - TurbolinksとReactを組み合わせてDOM diffを適用する
- react-bacon - Bacon.jsでReactを使用するための小さなモジュール
- msx - ReactのJSXトランスフォーマー、Mithrilへの出力呼び出しに合わせて調整
- React.withBackbone - React 16 readyバックボーンバインディング
- Backbone React Component
- react-backbone - Reactのためのバックボーン対応のミックスイン
- NestedReact - Backbone ViewsおよびNestedTypesモデルとの透過的な統合
- backbone-reaction - ReactとBackbone、そしてより強力なReactおよびBackboneの強化
- react.backbone - Backboneの移行を容易にするReactのプラグイン
- reactbone - BackboneのReact拡張機能
- backbone-react-ui - BackboneおよびBackboneページネーターで使用するためのReactコンポーネント
- react-events - Reactコンポーネントの宣言型マネージイベントバインディング
- react-mixin-manager - React Mixin登録マネージャー
- gsap-react-plugin - React.jsコンポーネントの状態をtweenするためのGSAPプラグイン
- react-topcoat by @plaxdan - Reactライブラリで構築されたトップコートCSSコンポーネント
- react-topcoat by @arnemart - トップコート用のReactコンポーネントのコレクション
- reactdown - マークダウン構文を使用してReactコンポーネントを作成
- react-jade - JadeをReactにコンパイル
- jade-react - JadeテンプレートをReact.DOM式にコンパイルします
- gulp-jade-react - GulpでJadeテンプレートをReact de-sugared JSXにコンパイルする
- sbt-reactjs - npmを使用したReact SBTプラグイン
- scalajs-react - Scala.jsとReact
- react-xtags - Reactを使用してxtagsを実装
- jreact - Java用React
- React.hiccup - sweet.jsで記述されたJSXの完全な代替
- react-play - JDK8のNashornを使用したPlayフレームワークでのReactコンポーネントのレンダリング
- rx-react - RxJSでReactを操作するユーティリティ
- react-with-di - DIを使用したReact.jsのプロトタイプ
- reactfire - Firebase統合を容易にするReactJSミックスイン
- firedux - Firebase + ReactJSのRedux
- react-clickdrag-mixin - ReactコンポーネントのClickDragミックスイン
- Rewrite the Admin UI of KeystoneJS in React
- react-masonry-mixin - Masonryのためのミックスイン
- react-packery-mixin - (Metafizzy) - Packeryのためのミックスイン
- react-dropzone - React.jsを使用したシンプルなHTML5ドラッグドロップゾーン
- aframe-react - A-Frame VR + React
- react-three - three.jsを使用してバインディングを反応させて3Dシーンを作成および制御
- react-three-renderer - Reactを使用してthree.jsキャンバスにレンダリングする
- react-threejs - ReactとThree.jsの間の最も単純なバインディング
- react-masonry-css - CSSによる高速Masonryレイアウト
- react-captcha - Google用のreact.js reCAPTCHA
- reaptcha - Google reCAPTCHA用のクリーンでモダンでシンプルなReactラッパー
- react-recaptcha-that-works - 動作するReactのreCAPTCHAブリッジ
フォーム
- React Forms
- react-formal - Reactのフォーム検証と値管理の改善、最小限の配線の提供
- react-forms - Reactのフォームライブラリ
- valuelink - 拡張されたReactリンクを備えたフル機能の双方向データバインディング
- wingspan-forms - Reactの動的フォームライブラリ
- newforms - Reactの同形フォーム処理
- formjs - Reactjsのフォームジェネレーター
- react-form-builder - React.jsのフォームビルダー
- plexus-form - JSONスキーマを使用して反応するための動的フォームコンポーネント
- tcomb-form - より少ないコードを記述するフォームを開発するためのUIライブラリ
- formsy-react - React JSのフォーム入力ビルダーおよびバリデーター
- Learn Raw React: Ridiculously Simple Forms
- Winterfell - Reactで検証済みで拡張可能な複雑なJSONベースのフォームを生成する
- Redux-Autoform - メタデータからRedux-Formsを動的に作成する
- uniforms - フォームを簡単に生成および検証するためのReactコンポーネントとヘルパーの束
- formik - Reactフォーム
- NeoForm - フォーム状態の管理と検証のためのモジュラーHOC
- react-jsonschema-form - JSONスキーマからWebフォームを構築するためのReactコンポーネント
- List View Select - React Nativeとネイティブコンポーネントの切り替え可能な選択ボックス
- Final Form ?
- formland - シンプルで柔軟性が高く、拡張可能な構成ベースのフォームジェネレーター
- react-reactive-form - ReactのAngularのようなリアクティブフォーム
- unform - ネストされたフィールド、検証など、制御されていないフォーム構造を作成するReactJSフォームライブラリ
- Formal - React Hook時代のエレガントなフォーム管理プリミティブ
オートコンプリート(入力補完)
- react-autocomplete by @rackt - WAI-ARIA準拠のReactオートコンプリート
- react-autosuggest by @moroshko - WAI-ARIA準拠のReact自動サジェストコンポーネント
- react-autocomplete by @eliseumds - ReactJS + RxJS
- react-autocomplete by @prometheusresearch - Reactに基づいたオートコンプリートウィジェット
- instatype by @gragland - シンプルなReactオートコンプリートコンポーネント
- downshift - シンプルで柔軟なWAI-ARIA準拠の拡張入力Reactコンポーネントを構築するためのプリミティブ
- React Bootstrap Typeahead - スタイル設定のためにBootstrapに依存し、もともとTwitterのtypeahead.jsに触発された、Reactベースのtypeahead
グラフィック
- react-art - Reactを使用してベクターグラフィックスを描画するためのJavaScriptライブラリ
- react-canvas - Reactコンポーネントのための高性能canvasレンダリング
- react-famous - Famo.usを使用した60 FPSの複雑な3DアニメーションUI
- react-kinetic - Reactを使用したKineticJS経由のHTML5 Canvas
- react-svg-morph - svgコンポーネントを別のものにモーフィングする
- react-hooks-svgdrawing - Reactフックを使用したSVG描画
モデルライブラリ
- mori - ClojureScriptの永続データ構造とサポートAPI
- NestedTypes - 「純粋なレンダリング」をサポートする高速可変モデル
- swarm - JavaScript複製モデル(MVCのM)ライブラリ
- caplet - JavaScriptモデルライブラリ
データ管理
- Immutable.js - JavaScript用の不変のデータコレクション
- cortex - Reactでデータを集中管理するためのJavaScriptライブラリ
- avers - 最新のクライアント側モデル抽象化ライブラリ
- imvvm - Reactの不変のModel-View-ViewModel
- morearty.js - 純粋なJavaScriptでのReactの状態管理の改善
- valuable - Reactの不変のデータストア
- react-resolver - Reactコンポーネントのデータを再帰的に遅延ロードする同形ライブラリ
- freezer-js - Reactの軽量でリアクティブな不変のデータ構造
- MobX - シンプルでスケーラブルな状態管理
- baobab - カーソルを使用したJavaScript永続的でオプションの不変データツリー
- baobab-react - BaobabのReact統合
- datascript - ClojureScriptの不変データベースとデータログクエリエンジン
- immstruct - Reactのようなコンポーネントベースのライブラリのトップからボトムのプロパティの履歴を持つ不変のデータ構造
- seamless-immutable - 通常のJS配列およびオブジェクトと後方互換性のあるJavaScriptの不変のデータ構造
- tydel - 型付きモデルとコレクション、Reactバインディング
- extendable-immutable - Immutable.jsデータ構造を拡張する
- statty - ReactおよびPreactアプリ用の小さくて控えめな状態管理ライブラリ
- Hydux - 「バッテリーを含む」ReactのElmライクステートマネージャー
- ReSub - より良いReactコンポーネントとデータストアを作成するためのライブラリ
- ProppyJS - Functional props構成のための小さなライブラリ
- WatermelonDB - 強力なReactおよびReact Nativeアプリ向けの次世代データベースで、数万件のレコードに対応し、高速性を維持
- Effector - 高速で強力なリアクティブ状態マネージャー。 シンプルで高速かつタイプセーフなコードを記述し、状態を簡単に管理
- reactn - 組み込みのグローバル状態管理
- immer - 現在の状態を変更し、次の不変状態を作成
地図
- react-googlemaps - GoogleマップへのReactインターフェース
- react-maps - Reactのマップコンポーネント
- react-google-maps - React.js Google Maps統合コンポーネント
- react-gmaps - React.js用のGoogleマップコンポーネント
- react-map-gl - MapboxGL JSのReactラッパー
- google-map-react - Googleマップと同形のReactコンポーネント
- react-mapbox-gl - Reactのためのmapbox-gl-jsラッパー
- google-maps-react - React、遅延読み込みの依存関係、現在位置ファインダー、およびフルスタックReactチームによるテスト駆動型アプローチを使用した宣言的なGoogle Map Reactコンポーネント
- react-leaflet - リーフレットマップのReactコンポーネント
- react-geo - react、antd、およびolを使用した地理関連コンポーネントのセット
- pigeon-maps - 外部依存関係のないReactJSマップ
統計・グラフ
- DevExtreme React Chart - BootstrapおよびMaterialデザイン用の高性能プラグインベースのReactチャート
- react-chartjs - chart.jsを使用した一般的なReactチャートコンポーネント
- react-stockcharts - ReactJSとd3による高度にカスタマイズ可能な株価チャート
- Number Picture - React&D3でアニメーション化された視覚化を構築するための低レベルのビルディングブロック
- Victory - インタラクティブなデータ視覚化を構築するための構成可能なReactコンポーネントのコレクション
- Recharts - すばらしい宣言型APIを備えたD3上に構築されたチャートライブラリ
- React-ApexCharts - ApexChartsのReactコンポーネント(インタラクティブなSVGチャートライブラリ)
- reaviz - D3.jsに基づくReactでの視覚化ライブラリ
- react-vis - Reactフレンドリー、高レベルでカスタマイズ可能で、表現力があり、業界に強いReact視覚化ライブラリー
- nivo - D3およびReactライブラリの上に構築された、豊富なデータ視覚化コンポーネントのセットを提供
- vx - 再利用可能な低レベルの視覚化コンポーネントのコレクション
- echarts-for-react - Reactの非常にシンプルなEChartsラッパー
- Chartify - CSSを使用してチャートを作成するためのReactプラグイン
- Semiotic - ReactとD3を組み合わせたデータ視覚化フレームワーク
- 投稿日:2019-12-05T08:32:35+09:00
Awesome React - Reactのオススメ記事・ライブラリ・ツール まとめ -
Awesome React
- この記事は次の日本語訳です(Reactの部分のみ抜粋)
公式
コミュニティ
オンラインでReactのコードを試せるサービス
チュートリアル
Reactのチュートリアル
- React Official Tutorial - 公式
- Using React in Visual Studio Code - ReactをVSCodeで使う
- Scrimba - Learn React for free interactively - ScrimbaのReactコース
- FreeCodeCamp React Challenges - FreeCodeCampのReactコース
- React Cheatsheet - チートシート
- React Patterns - Reactのコンポーネントのパターン集
- Setup Flow with React - ReactでFlowを使うセットアップ方法
React Hooksのチュートリアル
- React Hooks - 公式
- Replacing Redux with React Hooks and Context - ReduxをReact HooksとContextで置き換える
- React Hooks cheat sheet: Unlock solutions to common problems - React Hooksチートシート
- How to fetch data with React Hooks? - React Hooksで fetch APIを使うには?
- Easy to understand React Hook recipes - React Hooksのレシピ集
- Awesome React Hooks
React & TypeScript
パフォーマンス
- React Optimizing Performance - パフォーマンスの最適化
- Introducing the React Profiler - プロファイラーの紹介
- Optimizing React: Virtual DOM explained - 仮装DOMの説明
- A Definitive Guide to Optimize Major Performance issues in React - パフォーマンスの問題を最適化ガイド
- Twitter Lite and High Performance React Progressive Web Apps at Scale - Twitter Liteを例にした高パフォーマンスなPWAへの取り組み
- Using the React DevTools Profiler to Diagnose React App Performance Issues - React DevTools Profilerを使用してReactアプリのパフォーマンスの問題を診断する
- Top 5 Practices to Boost React Performance
- React is Slow, React is Fast: Optimizing react Apps in Practice - Reactアプリを最適化の実践
- Rendering large lists with react-window - react-windowで大量のリストを描画する
React内部の実装ついて
- Reconciliation - Reactの差分を検知するアルゴリズムについて
- React Fiber Architecture - Reactのコアアルゴリズムについて
- Build your own React - 独自のReactを構築するためのDIYガイド
- Inside Fiber: In-depth overview of the new reconciliation algorithm in React - Reactの新しい差分検知アルゴリズムの概要
ReactについてのQ&A
React Tools
React 開発ツール
- create-react-app - 1つのコマンドで最新のWebアプリをセットアップする
- react-starter-kit - webアプリ用テンプレート
- react-devtools - ChromeおよびFirefox開発ツールでのReactコンポーネント階層の検査
- react-hot-loader - Reactコンポーネントをリアルタイムで調整する
- react-loadable - promiseでコンポーネントを読み込むための高階層コンポーネント
- loadable-components - Reactコード分割を簡単にする、bundleサイズを縮小する
- reactotron - ReactおよびReact Nativeプロジェクトを検査するためのデスクトップアプリ
- storybook - UIコンポーネントの開発とテスト
- react-styleguidist - スタイルガイド付きのReactコンポーネント開発環境
- react-cosmos - 再利用可能なReactコンポーネントを作成するための開発ツール
- eslint-plugin-react - ESLintの特定のlintルールのプラグイン
- eslint-plugin-jsx-a11y - JSX要素のa11yルールの静的ASTチェッカー
- react-axe - Reactアプリケーションのアクセシビリティ監査
React フレームワーク
React スタイル
- styled-components - コンポーネントのスタイルに実際のCSSコードを記述できるようにするライブラリ
- emotion - JavaScriptを使用してCSSスタイルを記述するために設計されたライブラリ
- radium - Reactのインラインスタイルを管理するツールのセット
- jss - JavaScriptでスタイルシートを生成するためのライブラリ
React ルーティング
- react-router - Reactの宣言型ルーティング
- navi - Reactの宣言的な非同期ルーティング
- curi - 単一ページアプリケーション用のJavaScriptルーター
React UIコンポーネントライブラリ
- material-ui - Web開発を迅速かつ簡単にするためのコンポーネント
- ant-design - エンタープライズクラスのUIデザイン言語とReact UIライブラリ
- blueprint - Web用のReactベースのUIツールキット
- office-ui-fabric-react - Microsoft Webエクスペリエンスを構築するためのReactコンポーネント
- react-bootstrap - Reactで構築されたbootstrapコンポーネント
- reactstrap - Bootstrap 4のステートレスReactコンポーネント
- semantic-ui-react - Semantic-UIのReactコンポーネント
- react-fontawesome - Font Awesome 5 のReactコンポーネント
- Reakit - Reactのアクセス可能、構成可能、カスタマイズ可能なコンポーネント
- rsuite - エンタープライズシステム製品用の一連のReactコンポーネントライブラリ
- atlaskit - Atlassianデザインガイドラインに従って構築されたAtlassianの公式UIライブラリ
Reactの素晴らしいコンポーネント
- Awesome React Components list - 本当に素晴らしいReactコンポーネントとライブラリ
- react-select - Reactの選択コンポーネント
- react-dnd - Reactのドラッグアンドドロップ
- react-grid-layout - レスポンシブブレークポイントを備えたドラッグ可能でサイズ変更可能なグリッドレイアウト
- react-table - React向けの軽量で高速で拡張可能なデータグリッド
- react-data-grid - Reactで構築されたExcelのようなグリッドコンポーネント
- react-draggable - ドラッグ可能なReactコンポーネント
- react-resizable-and-movable - Reactのサイズ変更およびドラッグ可能なコンポーネント
- react-resizable - ハンドルでサイズ変更可能な単純なReactコンポーネント
- react-resizable-box - Reactのサイズ変更可能なコンポーネント
- react-sortable-pane - React用のソートおよびサイズ変更可能なペインコンポーネント
- react-dates - ウェブ向けの簡単に国際化可能でモバイル対応の日付選択ライブラリ
- react-big-calendar - カレンダーコンポーネント
- react-datepicker - Reactの日付選択ライブラリ
- react-list - 多用途の無限スクロールReactコンポーネント
- react-intl - Reactアプリの国際化
- react-i18next - Reactの国際化を正しく行うライブラリ
- react-aria-modal - 完全にアクセス可能なReactモーダル
- react-hotkeys - Reactの宣言的なホットキーとフォーカスエリア管理
- react-keydown - Reactコンポーネント用の軽量キーダウンラッパー
- react-joyride - アプリのガイドを作成するライブラリ
- react-virtualized - 大きなリストと表形式のデータを効率的にレンダリングするためのReactコンポーネント
- react-window - 大きなリストと表形式のデータを効率的にレンダリングするためのReactコンポーネント
- react-text-mask - React用Inputマスク
- react-loading-skeleton - アプリに自動的に適応するスケルトン画面を作成するライブラリ
- react-spinkit - 読み込み表示のCSSアニメーションのReactライブラリ
- rheostat - Reactで構築されたアクセス可能なスライダーコンポーネント
- qrcode.react - Reactで使用するQRコードのコンポーネント
Reactコマンドラインツール
- ink - React用のインタラクティブなコマンドラインアプリ
- react-blessed - ターミナルインターフェイスライブラリのReactレンダラー
Reactテストツール
- jest - JavaScriptテストフレームワーク
- enzyme - React用のJavaScriptテストユーティリティ
- react-testing-library - シンプルで完全なReact DOMテストユーティリティ
- react-hooks-testing-library - 優れたテストプラクティスを促進するReact Hooksテストユーティリティ
- majestic - JestのためのGUI
React Libraries
- react-border-wrapper - Reactのdiv境界に沿って要素を配置するためのラッパー
- react-magic - ReactでプレーンなHTMLにAJAXを使用できるようにするライブラリ
- react-toolbox - Googleのマテリアルデザイン仕様を実装する一連のReactコンポーネント
- tcomb-react - Reactコンポーネントのすべてのpropsをチェックできるライブラリ
- react-responsive - レスポンシブデザインに対応するメディアクエリ
- react-cursor - Reactで使用するためのFunctional Stateの管理の抽象化
- Omniscient.js - 不変データの高速トップダウンレンダリングのためのReactコンポーネントの抽象化
- Touchstonejs - 美しいハイブリッドモバイルアプリを開発するためのReact.jsを搭載したUIフレームワーク。
- Elemental - React.js WebサイトおよびアプリのUIツールキット
- StateTrooper - CSPでReactアプリケーションの状態を一元管理
- Preact - ReactのモダンなAPIを使用できる高速3kbのReactの代替ライブラリ
- riotjs - Reactのような3.5KBのユーザーインターフェイスライブラリ
- Maple.js - Webコンポーネントの概念をReactにもたらす
- react-i13n - Reactアプリケーションを計装するための、高性能でスケーラブルでプラグ可能なアプローチ
- react-icons - 人気のあるアイコンパックのsvgアイコン
- Keo - Reactコンポーネントを作成するためのより機能的なDekuアプローチのためのプレーン関数
- Bit - アプリケーション間でリアクションおよびその他のWebコンポーネントを管理および使用するための仮想リポジトリ
- AtlasKit - AtlassianのReact UIライブラリ
- ReactiveSearch - ElasticsearchのためのUIコンポーネントライブラリ
- Slate - リッチテキストエディターを構築するための完全にカスタマイズ可能なフレームワーク
- react-json-schema - JSON定義を公開するReactコンポーネントにマッピングして、JSONからReact要素を構築する
- compose-state - Reactで複数のsetStateまたはgetDerivedStateFromPropsアップデーターを作成する
- PrimeReact - Reactの最も完全なUIフレームワーク
- react-lodash - ReactコンポーネントとしてのLodash
- react-helmet - Reactのドキュメントヘッドマネージャー
- Stator - Reactの組み込みサポートを備えたシンプルでプレーンなJavaScript状態管理
- ClearX - 学習曲線がゼロでReact向けの高速で簡単な状態管理
- react-snap - SPAのためのゼロ構成フレームワークに依存しない静的事前レンダリング
- Draft.js - テキストエディターを構築するためのReactフレームワーク
- refract - リアクティブプログラミングのパワーを制御して、コンポーネントを満たす
- react-desktop - Reactで構築されたOS XおよびWindows UIコンポーネント
- Reapop - React&Redux通知システム
- react-extras - Reactを使用するための便利なコンポーネントとユーティリティ
- react-instantsearch - AlgoliaによるReactおよびReact Nativeアプリケーションの超高速検索
- uppy - Webブラウザー用の次のオープンソースファイルアップローダー
- react-motion - アニメーションの問題を解決するバネ
- react-esi - ReactおよびNext.jsの非常に高速なサーバー側レンダリング
Reactインテグレーション
- React Rails - ReactをRailsと使うための柔軟なツール
- ReactJS.NET - ReactコンポーネントのJSXコンパイルおよびサーバー側レンダリング用の.NETライブラリ
- React ASP.NET Boilerplate - ASP.NET Coreを使用して同じReactアプリケーションを構築するためのテンプレート
- React Bootstrap Components Playground - react-bootstrapの型チェック
- om - ReactのClojureScript UIフレームワークとクライアント/サーバーアーキテクチャ
- quiescent - React上の軽量ClojureScript
- Reagent - React.jsへの最小限のClojureScriptインターフェース
- react-haskell - HaskellのReactバインディング
- Express React views
- Express Coffee-React views - サーバー上でCofee-Reactをレンダリングする
- React Page Middleware
- ngReact - AngularのReactコンポーネント
- React Laravel
- coffee-react-transform - CoffeescriptのReact JSXサポートを提供
- sprockets-coffee-react - CJSXのスプロケットプリプロセッサ
- react-kup - coffeescriptのjsxに代わるシンプルで非侵入的な代替手段
- turbo-react - TurbolinksとReactを組み合わせてDOM diffを適用する
- react-bacon - Bacon.jsでReactを使用するための小さなモジュール
- msx - ReactのJSXトランスフォーマー、Mithrilへの出力呼び出しに合わせて調整
- React.withBackbone - React 16 readyバックボーンバインディング
- Backbone React Component
- react-backbone - Reactのためのバックボーン対応のミックスイン
- NestedReact - Backbone ViewsおよびNestedTypesモデルとの透過的な統合
- backbone-reaction - ReactとBackbone、そしてより強力なReactおよびBackboneの強化
- react.backbone - Backboneの移行を容易にするReactのプラグイン
- reactbone - BackboneのReact拡張機能
- backbone-react-ui - BackboneおよびBackboneページネーターで使用するためのReactコンポーネント
- react-events - Reactコンポーネントの宣言型マネージイベントバインディング
- react-mixin-manager - React Mixin登録マネージャー
- gsap-react-plugin - React.jsコンポーネントの状態をtweenするためのGSAPプラグイン
- react-topcoat by @plaxdan - Reactライブラリで構築されたトップコートCSSコンポーネント
- react-topcoat by @arnemart - トップコート用のReactコンポーネントのコレクション
- reactdown - マークダウン構文を使用してReactコンポーネントを作成
- react-jade - JadeをReactにコンパイル
- jade-react - JadeテンプレートをReact.DOM式にコンパイルします
- gulp-jade-react - GulpでJadeテンプレートをReact de-sugared JSXにコンパイルする
- sbt-reactjs - npmを使用したReact SBTプラグイン
- scalajs-react - Scala.jsとReact
- react-xtags - Reactを使用してxtagsを実装
- jreact - Java用React
- React.hiccup - sweet.jsで記述されたJSXの完全な代替
- react-play - JDK8のNashornを使用したPlayフレームワークでのReactコンポーネントのレンダリング
- rx-react - RxJSでReactを操作するユーティリティ
- react-with-di - DIを使用したReact.jsのプロトタイプ
- reactfire - Firebase統合を容易にするReactJSミックスイン
- firedux - Firebase + ReactJSのRedux
- react-clickdrag-mixin - ReactコンポーネントのClickDragミックスイン
- Rewrite the Admin UI of KeystoneJS in React
- react-masonry-mixin - Masonryのためのミックスイン
- react-packery-mixin - (Metafizzy) - Packeryのためのミックスイン
- react-dropzone - React.jsを使用したシンプルなHTML5ドラッグドロップゾーン
- aframe-react - A-Frame VR + React
- react-three - three.jsを使用してバインディングを反応させて3Dシーンを作成および制御
- react-three-renderer - Reactを使用してthree.jsキャンバスにレンダリングする
- react-threejs - ReactとThree.jsの間の最も単純なバインディング
- react-masonry-css - CSSによる高速Masonryレイアウト
- react-captcha - Google用のreact.js reCAPTCHA
- reaptcha - Google reCAPTCHA用のクリーンでモダンでシンプルなReactラッパー
- react-recaptcha-that-works - 動作するReactのreCAPTCHAブリッジ
フォーム
- React Forms
- react-formal - Reactのフォーム検証と値管理の改善、最小限の配線の提供
- react-forms - Reactのフォームライブラリ
- valuelink - 拡張されたReactリンクを備えたフル機能の双方向データバインディング
- wingspan-forms - Reactの動的フォームライブラリ
- newforms - Reactの同形フォーム処理
- formjs - Reactjsのフォームジェネレーター
- react-form-builder - React.jsのフォームビルダー
- plexus-form - JSONスキーマを使用して反応するための動的フォームコンポーネント
- tcomb-form - より少ないコードを記述するフォームを開発するためのUIライブラリ
- formsy-react - React JSのフォーム入力ビルダーおよびバリデーター
- Learn Raw React: Ridiculously Simple Forms
- Winterfell - Reactで検証済みで拡張可能な複雑なJSONベースのフォームを生成する
- Redux-Autoform - メタデータからRedux-Formsを動的に作成する
- uniforms - フォームを簡単に生成および検証するためのReactコンポーネントとヘルパーの束
- formik - Reactフォーム
- NeoForm - フォーム状態の管理と検証のためのモジュラーHOC
- react-jsonschema-form - JSONスキーマからWebフォームを構築するためのReactコンポーネント
- List View Select - React Nativeとネイティブコンポーネントの切り替え可能な選択ボックス
- Final Form ?
- formland - シンプルで柔軟性が高く、拡張可能な構成ベースのフォームジェネレーター
- react-reactive-form - ReactのAngularのようなリアクティブフォーム
- unform - ネストされたフィールド、検証など、制御されていないフォーム構造を作成するReactJSフォームライブラリ
- Formal - React Hook時代のエレガントなフォーム管理プリミティブ
オートコンプリート(入力補完)
- react-autocomplete by @rackt - WAI-ARIA準拠のReactオートコンプリート
- react-autosuggest by @moroshko - WAI-ARIA準拠のReact自動サジェストコンポーネント
- react-autocomplete by @eliseumds - ReactJS + RxJS
- react-autocomplete by @prometheusresearch - Reactに基づいたオートコンプリートウィジェット
- instatype by @gragland - シンプルなReactオートコンプリートコンポーネント
- downshift - シンプルで柔軟なWAI-ARIA準拠の拡張入力Reactコンポーネントを構築するためのプリミティブ
- React Bootstrap Typeahead - スタイル設定のためにBootstrapに依存し、もともとTwitterのtypeahead.jsに触発された、Reactベースのtypeahead
グラフィック
- react-art - Reactを使用してベクターグラフィックスを描画するためのJavaScriptライブラリ
- react-canvas - Reactコンポーネントのための高性能canvasレンダリング
- react-famous - Famo.usを使用した60 FPSの複雑な3DアニメーションUI
- react-kinetic - Reactを使用したKineticJS経由のHTML5 Canvas
- react-svg-morph - svgコンポーネントを別のものにモーフィングする
- react-hooks-svgdrawing - Reactフックを使用したSVG描画
モデルライブラリ
- mori - ClojureScriptの永続データ構造とサポートAPI
- NestedTypes - 「純粋なレンダリング」をサポートする高速可変モデル
- swarm - JavaScript複製モデル(MVCのM)ライブラリ
- caplet - JavaScriptモデルライブラリ
データ管理
- Immutable.js - JavaScript用の不変のデータコレクション
- cortex - Reactでデータを集中管理するためのJavaScriptライブラリ
- avers - 最新のクライアント側モデル抽象化ライブラリ
- imvvm - Reactの不変のModel-View-ViewModel
- morearty.js - 純粋なJavaScriptでのReactの状態管理の改善
- valuable - Reactの不変のデータストア
- react-resolver - Reactコンポーネントのデータを再帰的に遅延ロードする同形ライブラリ
- freezer-js - Reactの軽量でリアクティブな不変のデータ構造
- MobX - シンプルでスケーラブルな状態管理
- baobab - カーソルを使用したJavaScript永続的でオプションの不変データツリー
- baobab-react - BaobabのReact統合
- datascript - ClojureScriptの不変データベースとデータログクエリエンジン
- immstruct - Reactのようなコンポーネントベースのライブラリのトップからボトムのプロパティの履歴を持つ不変のデータ構造
- seamless-immutable - 通常のJS配列およびオブジェクトと後方互換性のあるJavaScriptの不変のデータ構造
- tydel - 型付きモデルとコレクション、Reactバインディング
- extendable-immutable - Immutable.jsデータ構造を拡張する
- statty - ReactおよびPreactアプリ用の小さくて控えめな状態管理ライブラリ
- Hydux - 「バッテリーを含む」ReactのElmライクステートマネージャー
- ReSub - より良いReactコンポーネントとデータストアを作成するためのライブラリ
- ProppyJS - Functional props構成のための小さなライブラリ
- WatermelonDB - 強力なReactおよびReact Nativeアプリ向けの次世代データベースで、数万件のレコードに対応し、高速性を維持
- Effector - 高速で強力なリアクティブ状態マネージャー。 シンプルで高速かつタイプセーフなコードを記述し、状態を簡単に管理
- reactn - 組み込みのグローバル状態管理
- immer - 現在の状態を変更し、次の不変状態を作成
地図
- react-googlemaps - GoogleマップへのReactインターフェース
- react-maps - Reactのマップコンポーネント
- react-google-maps - React.js Google Maps統合コンポーネント
- react-gmaps - React.js用のGoogleマップコンポーネント
- react-map-gl - MapboxGL JSのReactラッパー
- google-map-react - Googleマップと同形のReactコンポーネント
- react-mapbox-gl - Reactのためのmapbox-gl-jsラッパー
- google-maps-react - React、遅延読み込みの依存関係、現在位置ファインダー、およびフルスタックReactチームによるテスト駆動型アプローチを使用した宣言的なGoogle Map Reactコンポーネント
- react-leaflet - リーフレットマップのReactコンポーネント
- react-geo - react、antd、およびolを使用した地理関連コンポーネントのセット
- pigeon-maps - 外部依存関係のないReactJSマップ
統計・グラフ
- DevExtreme React Chart - BootstrapおよびMaterialデザイン用の高性能プラグインベースのReactチャート
- react-chartjs - chart.jsを使用した一般的なReactチャートコンポーネント
- react-stockcharts - ReactJSとd3による高度にカスタマイズ可能な株価チャート
- Number Picture - React&D3でアニメーション化された視覚化を構築するための低レベルのビルディングブロック
- Victory - インタラクティブなデータ視覚化を構築するための構成可能なReactコンポーネントのコレクション
- Recharts - すばらしい宣言型APIを備えたD3上に構築されたチャートライブラリ
- React-ApexCharts - ApexChartsのReactコンポーネント(インタラクティブなSVGチャートライブラリ)
- reaviz - D3.jsに基づくReactでの視覚化ライブラリ
- react-vis - Reactフレンドリー、高レベルでカスタマイズ可能で、表現力があり、業界に強いReact視覚化ライブラリー
- nivo - D3およびReactライブラリの上に構築された、豊富なデータ視覚化コンポーネントのセットを提供
- vx - 再利用可能な低レベルの視覚化コンポーネントのコレクション
- echarts-for-react - Reactの非常にシンプルなEChartsラッパー
- Chartify - CSSを使用してチャートを作成するためのReactプラグイン
- Semiotic - ReactとD3を組み合わせたデータ視覚化フレームワーク
- 投稿日:2019-12-05T08:29:07+09:00
【Svelte3入門】ToDoリストをチュートリアルと照らし合わせて作ろみゃあ!
はじめよっけ!
この記事はAteam Brides Inc. Advent Calendar 2019 6日目の記事です。
こんにちは。株式会社エイチームブライズの @mkin です。
さて、今日は React や Vue よりも早いと言われている Svelte を使って簡単なアプリを作っていきます。
この記事は実際に私が ToDoリストを作った順番に、チュートリアルを逆引きしながら作った実録でもあるので、読むだけでも開発体験をトレースできるんじゃないかと、淡く期待しています
React も Vue も好きな筆者が Svelte を触った感想は「...めっちゃ分かりやすいがぁ!!
」というもの。この開発体験を少しでも多くの方に共有したくてこの記事を書きます。
※Svelte は2019-04-23にリリースされ大幅に改善したバージョン3を指します。
Svelte ってなんなのー?
私も数週間前までその存在を知りませんでした。
職場のフレンズたちが Svelte で盛り上がっているとき、私は冷めた目をしていました。
でも、知らないものを批判しちゃいかんと思い直し、まず調べたのがこちら。Svelte がホームページで謳っていることは次の3つ...
- Write less code: より少ないコードで
- No virtual DOM: 仮想DOMを使わずに
- Truely reactive: 真のリアクティブ
順に説明しますね。
1. Write less code: より少ないコードで
単純な計算機能ですが、これを Svelte は React と比べて32%、Vue と比べて55% のコード量で実装できます。
- 442文字: React
- 263文字: Vue
- 145文字: Svelte
2. No virtual DOM: 仮想DOMを使わずに
これは大事なポイントですが、 Svelte はコンパイラーであり、React や Vue のようなフロントエンドフレームワークではありません。これにより、クライアントへ渡されるのは純粋な HTML と javascript と css になり、余分なオーバーヘッドを無くして高速に動きます。余分なオーバーヘッドとはフレームワーク自体の転送容量や、仮想DOMの生成時間、その使用メモリを指します。
3. Truely reactive: 真のリアクティブ
Svelte では 1と2のおかげで React / Vue のように複雑な状態管理を意識せずに書けます。実際、チュートリアルを幾つかやるだけで、その簡潔な書き方におったまげるでしょう。
参考までに、@so99ynoodles さんの記事「ReactとVueを改善したSvelteというライブラリーについて」によると
Svelteは速く、軽いです。
ベンチマークでReactの35倍、Vueの50倍速いです。
Svelteはコンパイラーであるため、実質ライブラリーとしての容量は0kbです。とのこと
開発環境を作ったるがや!
前置きはここまでにして、さっそく開発を始めていきましょう。
- 私の開発環境はこちらです。
- mscOS Mojave
- Visual Studio Code
- npx v6.13.1
Svelte プロジェクトを作成しよっけ!
簡単に開発環境を作るために「The Svelte 3 Quickstart Tutorial」を見ながら進めました。
まずは、以下のコマンドを実行してください。console# ワークスペースへ移動(好きな場所でOK) mkdir svelte cd svelte # Svelteプロジェクトを作成して関連パッケージをインストールする npx degit sveltejs/template todolist cd todolist/ npm install # VSCodeで開く code .そしたら、こんなプロジェクトができているので、、、
さっそく動かしてみましょう。
npm run dev
をコンソールで実行するとローカルホストが起動するので
http://localhost:5000/
にブラウザでアクセスしてください。
下記のように表示されたら成功。あなたの Svelte 生活の始まりですっ実装に入る前に...Svelte の拡張機能を入れとこっけ!
VSCode で開発するようなら、以下の拡張機能を入れておくとインテリセンスやシンタックスハイライトが効き、開発が捗るでしょう。
Svelte
Svelte 3 Snippets
ToDoリストの大枠を組み立ててこっけー
ToDoリストに求める機能はそれほど多くないので、大枠からざっくり作っていこうと思いました。
(逆に大きな機能のときは、それらを構成する機能をテスタブルに作り、終盤でつないでいくことが多いです。)
ということで、まず手始めに知っておいてほしいことは...基本構成、それは HTML、script、そして style だがや!
/src/App.svelte<!-- 自動生成された元の内容はガバっと変えていいよ! --> <!-- HTML部 --> <div> 絞り込み: <button>すべて</button> <button>未完了</button> <button>完了</button> </div> <div> <input type="text"> <button>タスク追加</button> </div> <div> <ul> <li> <input type="checkbox"> レストランを予約する </li> <li> <input type="checkbox"> サプライズ用の指輪を買う </li> <li> <input type="checkbox"> フラッシュモブダンスを練習する </li> </ul> </div> <script> // 後で記述するよ </script> <style> /* TODO: CSS得意なフレンズに頼む */ /* https://svelte.dev/tutorial/styling */ </style>ここまでは特に何も特別なことはありません。ただ、チュートリアルではscript、style、HTMLの構成でしたが、私が少し Nuxt.js を触っていたこともあり、順番を変えています。
さて、上記の実装をしたら、こんなシンプルでハッピーなToDoリストの雛形ができます
Svelte の機能を使ってToDoリストに機能をつけてこっかー
大枠が完成したところで、以下の手順で機能を実装していきたいと思います。
- タスクの直書きを配列に変更する
- 「タスク追加」ボタンでタスクを追加する
- 「絞り込み」機能で表示対象を切り替える
1. タスクの直書きを配列に変更する
実際のシステムであればサーバからデータを取得するのですが、
それは一旦置いといて、サクッと小さく動くものを作りたいと思いました。/src/App.svelte<ul> - <li> - <input type="checkbox"> レストランを予約する - </li> - <li> - <input type="checkbox"> サプライズ用の指輪を買う - </li> - <li> - <input type="checkbox"> フラッシュモブダンスを練習する - </li> + {#each todoList as todo (todo.id)} + <li> + <input type="checkbox" bind:checked={todo.done}> {todo.title} + </li> + {/each} </ul> <script> - // 後で記述するよ + let todoList = [ + { id: 0, done: false, title: 'レストランを予約する'}, + { id: 1, done: false, title: 'サプライズ用の指輪を買う'}, + { id: 2, done: false, title: 'フラッシュモブダンスを練習する'}, + ] </script>ここでは、以下のチュートリアルが役に立ちます。
- Binding / Text inputs:
{todo.title}
変数の値を表示してみよう。- Binding / Checkbox inputs:
{todo.done}
変数の値と checkbox の値を紐付けてみよう。- Logic / Keyed each blocks: ループ処理をしてみよう。
#each
句で各ToDoタスクと(todo.id)
を紐付けることで、Svelte に変化を検知させることができるよ。動かしてみると、先程と表示は変わりませんが、配列からToDoリストを表示するように変更できました。
2. 「タスク追加」ボタンでタスクを追加する
次に「タスク追加」ボタンに対してクリックイベントを追加していきたい。(自分に負けない!)
/src/App.svelte<div> - <input type="text"> - <button>タスク追加</button> + <input type="text" bind:value={title}> + <button on:click={() => add()}>タスク追加</button> </div> ・・・ <script> ... + let title = '' + function add() { + todoList = [...todoList, + { + id: todoList.length, + done: false, + title + }] + } </script>ここでは、以下のチュートリアルが役に立ちます。
- Binding / Text inputs: ←前述と同じ。input 要素に入力した値と title 変数を紐付けてみよう。
- Reactivity / Assignments: button 要素のクリックイベントとjs関数を紐付けてみよう。
3. 「絞り込み」機能で表示対象を切り替える
さぁ、最後の工程です! フィルタリングして見たい情報に絞り込んでやろうではありませんかっ!
(おーっ!!!!!)
/src/App.svelte<div> 絞り込み: - <button>すべて</button> - <button>未完了</button> - <button>完了</button> + <button on:click={() => { condition = null }}>すべて</button> + <button on:click={() => { condition = false }}>未完了</button> + <button on:click={() => { condition = true }}>完了</button> + </div> - {#each todoList as todo (todo.id)} + {#each filteredTodoList(todoList, condition) as todo (todo.id)} <li> <input type="checkbox" bind:checked={todo.done}> {todo.title} </li> {/each} <script> ... + let condition = null + + $: filteredTodoList = (todoList, condition) => { + return condition === null ? todoList : todoList.filter(t => t.done === condition) + } + </script>ここでは、以下のチュートリアルが役に立ちます。
- Reactivity / Declarations: 変数の値を監視して動的に差分変更してみよう。
ここまでできたらToDoも完成です!
さぁ!みなさんもToDoを追加していきましょう!!ちょっと待って!! 何かおかしいがー
さっきの動画で何かマズい点あったの気づきました?
そうです。そもそも恋人がいないんですよ!
そうです。動かして分かったんですが、このToDoリストには具合が悪い点がいくつかあったんです。それは...
- 初期カーソルが タスク入力欄にフォーカスされてないから入力しづらい
- 「タスク追加」ボタンをクリックした後にタスク入力欄がクリアされない
そこで、最後のお仕置きをしたいと思いました。
初期化処理で操作性を高めたいがー
上記の問題は初期化処理を追加することで解決しました。
では、さっそく.../src/App.svelte<div> - <input type="text" bind:value={title}> + <input type="text" bind:value={title} bind:this={initFocus}> <button on:click={add}>タスク追加</button> </div> <script> + import { onMount } from 'svelte' + + onMount(() => { + init() + }) + + let initFocus = null + + function init() { + title = '' + initFocus.focus() + } function add() { todoList = [...todoList, { id: todoList.length, done: false, title }] + init() } </script>※うまく反映されない場合はブラウザのキャッシュクリアをしてみてください。
ここでは、以下のチュートリアルが役に立ちます。
- Lifecycle / onMount: コンポーネントのライフサイクルを理解しましょう。コンポーネントが最初にDOM描画された後に onMountハンドラで書いた処理を実行するよ。
- Bindings / This:
bind:this={変数}
で何でも好きな要素と紐付けてみよう。完成版だぎゃー!!!!!!!!!
/src/App.svelte(完成版)<!-- HTML部 --> <div> 絞り込み: <button on:click={() => { condition = null }}>すべて</button> <button on:click={() => { condition = false }}>未完了</button> <button on:click={() => { condition = true }}>完了</button> </div> <div> <input type="text" bind:value={title} bind:this={initFocus}> <button on:click={() => add()}>タスク追加</button> </div> <div> <ul> {#each filteredTodoList(todoList, condition) as todo (todo.id)} <li> <input type="checkbox" bind:checked={todo.done}> {todo.title} </li> {/each} </ul> </div> <script> import { onMount } from 'svelte' let title = '' let initFocus = null let condition = null let todoList = [ { id: 0, done: false, title: 'レストランを予約する'}, { id: 1, done: false, title: 'サプライズ用の指輪を買う'}, { id: 2, done: false, title: 'フラッシュモブダンスを練習する'}, ] onMount(() => { init() }) function init() { title = '' initFocus.focus() } function add() { todoList = [...todoList, { id: todoList.length, done: false, title }] init() } $: filteredTodoList = (todoList, condition) => { return condition === null ? todoList : todoList.filter(t => t.done === condition) } </script> <style> /* TODO: CSS得意なフレンズ絶賛募集中!! */ /* https://svelte.dev/tutorial/styling */ </style>最後に、Svelte いいがやっ!
コード量が少ないから見晴らしがよくて、とっつきやすいんじゃないかなと思います
Svelte でもコンポーネント管理できるし、Storybook for Svelteもあるのでデザインシステムも作れる。そのうえ、SSRとしてSapper という Next/Nuxt のようなフレームワークも用意されている。React Native / Vue Native よろしく Svelte Naitveというのもある。(誰だ!やり過ぎって言ったやつ! 俺も同感だよっ!)
React / Vue を触ったことがある方にはすごく馴染みやすい技術だと思うので、試してみてもらえると嬉しいです!また、昨日の @oekazuma の記事「君はVue,Reactの次に来るSvelteを知っているか?」も併せて読んでいただけると嬉しいです
それでは、明日は @fussy113 の「サイト速度改善、実装編」(仮)の予定です。どうぞご期待ください
私たちのチームで働こまい?
エイチームは、インターネットを使った多様な技術を駆使し、幅広いビジネスの領域に挑戦し続ける名古屋の総合IT企業です。
そのグループ会社である株式会社エイチームブライズでは、一緒に働く仲間を募集しています!上記求人をご覧いただき、少しでも興味を持っていただけた方は、まずはチャットでざっくばらんに話をしましょう。
技術的な話だけでなく、私たちが大切にしていることや、お任せしたいお仕事についてなどを詳しくお伝えいたします!Qiita Jobsよりメッセージお待ちしております!
- 投稿日:2019-12-05T00:04:29+09:00
Figma ✕ React Storybook で作るプロトタイピング & スタイルガイド
アプリを開発する前に予め、開発の全体像を把握するためにプロトタイプを作成します。
プロトタイピングツールで作成したUIは、実際のアプリ開発にも流用できるため効率的です。今回は簡単な
写真共有Webブラウザアプリ
を制作すると仮定して、
- プロトタイピングツール
Figma
でプロトタイプ作成Reactコンポーネント
への落とし込みStorybook
での管理という一連の流れを実際に実装しながら
Figma
やStorybook
を導入することでどういったメリットがあるのか・どういったことができるのかの検証を行います。作成したプロトタイプの全体像
最初にどんなアプリなのかをスクリーンショットで提示してから、詳細な解説を進めていきます。
基本的なアプリに最低限必要な認証
・一覧表示
・登録
・編集
機能をプロトタイピングで再現しました。
マテリアルデザイン(Material-ui)をベースとしています。ログイン画面
- ユーザーサインイン
- ユーザー新規登録
- パスワードリセット
アルバム一覧・投稿画面
- アルバム一覧表示
- アルバム投稿
- アルバム編集
- アルバム削除
なぜFigmaを使うのか
Figma公式サイト
https://www.figma.com/プロトタイピングツールには
Sketch
・AdobeXD
など様々な種類がありますが、今回Figma
を選択したのは以下の理由からです。
- ブラウザからアクセスしサインインするだけで、ほとんどの機能を無料で使える
- コンポーネント・スタイルの管理が楽そう
- 機能面でSketchやXDと遜色なさそう
- リアルタイムコラボレーションを試してみたかった
- 話題の
web assembly
で記述されているwebアプリの操作性を実際に体験してみたかったFigmaで作るスタイルガイド
若干我流かもしれませんが
Atomic Design
を意識して、スタイルガイドを作成してみました。後ほど、Material-ui
でコードを組む予定だったので、フォント・カラーなどの命名・パターンは極力Material-uiデフォルトのものを使用し齟齬が出ないようにしました。
Figmaではカラー・フォントはローカルスタイルとして定義することができ、定義されたスタイルをボタンやフォームなどに適用すれば、同一のスタイルを一括で変更したりと変更に強いデータを作成することが可能です。フォント
Material-uiにもともと定義されているタイポグラフィ+タイトルのフォントを定義。
カラー
- ベースカラー → Material-uiのオリジナルカラー
grey
のカラーパターン- メインカラー → 独自のネイビー系の配色
dark
・main
・light
の3パターン- アクセントカラー → 独自のオレンジ系の配色
dark
・main
・light
の3パターンアイコン・ボタン・フォーム
Figma便利機能
Figmaは奥が深く、いろいろと便利機能があるのですが、私が利用するなかで特に便利だと思った機能について解説を行います。
コンポーネント
図形やテキストなどのパーツをまとめたものをコンポーネントとして定義することができます。
画面上部メニューにある菱形アイコンをクリックするか、パーツを全て選択右クリックCreate Component
で簡単にコンポーネントを作成できます。
コンポーネントはコピーすることで、インスタンスを生成することができ、コピー元コンポーネント(マスターコンポーネント)の変更がリアルタイムで反映されるようになります。
生成されたインスタンスはパーツの位置のみは固定で、以下項目についてはオーバーライドして独自のコンポーネントを作成することが可能です。
- カラー
- 画像
- テキストの内容
- コンポーネントのサイズ
コンストレイント
上記のコンポーネント機能で、インスタンスを作成しコンポーネントのサイズ感を変更したい。しかし、コンポーネントのサイズを変更すると図形の比率や配置が変更されてしまった。そんなときに使えるのがコンストレイント機能です。コンストレイント機能を使うと、「左上」「右上」「左下」「右下」「中央」の中から、位置固定の基準位置を設定することができます。
コンポーネントの整列
プロトタイプを作成していると、複数のコンポーネント間を一発で調整したい時があるはずです。Figmaなら整列ボタンを使わなくても直感的にドラックアンドドロップで調整できるので作業効率が上がります。Illustratorやphotoshopではこんな機能なかったのですごく便利に感じました。
適当に配置した、オブジェクトをいい感じに整列してくれる「Tidy Up」もそこそこ便利です。整列ボタンから選択できます。
画像の一括配置
画像も複数画像を選択してサクサク配置することができます。アプリのイメージを変えたいなと思った時も10秒とかからず変更することができます。ただ、Sketchのようにテキストの一括流し込みができないのは残念です。
プロトタイピング
Figmaでは画面のレイアウトを作成したら、そのままプロトタイピングも実装できます。サイドバーメニューから
Prototype
タブを選択し、あとはトリガーとなるボタンまたはフォームから遷移先のフレームに以下画像のように動線を結べば「クリックしたら画面遷移」や「ホバーしたらコンポーネント表示」などを実現させることができます。
アニメーションについては複雑な動作はできませんが、プロトタイピングの段階では画面遷移だけわかれば良いということがほとんどだと思うので私は十分だと思いました。フェードイン・アウトやムーブイン・アウトなど基本的動作は普通にできます。
コラボレーション
Figmaの一番の強みコラボレーション機能についてです。今回のアプリ制作は1人で作業していたためあまり効力を発揮しませんでしたが、試しに2台PCと2アカウントを用意してコラボレーション機能を試してみました。タイムラグが発生して使いにくいのではないかと思っていましたが、Google Documentのようにデザイン変更はリアルタイムで反映されストレスなく作業を行うことができました。何より、ファイルの受け渡しなく同時平行で複数人が作業・コメントできるのは作業効率や管理コスト面で相当便利な機能だと思います。
なぜStoryBookを使うのか
StoryBook公式サイト
https://storybook.js.org/StoryBookは
UI Component 管理ツール
という位置づけです。スタイルガイドを作成するだけなら、上記で解説したFigma
でも可能です。しかし、実際運用・保守の観点で考えるとデザイン改修の際にFigmaファイルを修正して、その上でアプリのコードを修正するとなると2度手間になってしまいます。Storybook
を利用するとアプリのコードをそのままスタイルガイドにできるので、スタイルガイドを修正する=アプリのコードを修正するということになり「アプリ側のコードだけしか修正されずスタイルガイドの意味がなくなってしまった」というリスクを防ぐことが可能になります。
Figmaはベータ版の段階でざっくりとスタイルガイドを作成する、ある程度案が固まって実際にコードを書き始めたらStorybookでしっかりとスタイルガイドを作り込んで運用するといった感じになると思います。StorybookはFigmaのようにGUIベースではなくコードベースなので、それなりに学習コストもかかりますが、作成したコンポーネントはそのままアプリで使えますのでスタイルガイド作成作業が全く無駄になってしまうということはないと思います。
Storybook for Reactの導入
Storybookを導入したいreactアプリケーションのプロジェクトルートで以下コマンドを入力すると自動でStorybookのsettingを行ってくれます。
shellnpx -p @storybook/cli sb init --type react以下コマンドでStorybookを起動するとブラウザでスタイルガイドが開きます。
shellyarn storybook
typescript
を使用する場合は、まず.storybook
配下の2つのファイルに変更を加えます。
(ファイルが存在しなければ追加します).storybook/webpack.config.jsmodule.exports = ({ config }) => { config.module.rules.push({ test: /\.(ts|tsx)$/, use: [ { loader: require.resolve('babel-loader'), options: { presets: [['react-app', { flow: false, typescript: true }]], }, }, { loader: require.resolve('react-docgen-typescript-loader'), }, ], }); config.resolve.extensions.push('.ts', '.tsx'); return config; };.storybook/config.jsimport { configure } from '@storybook/react'; // automatically import all files ending in *.stories.js configure(require.context('../stories', true, /\.stories\.tsx$/), module);次にプロジェクトルートに存在する
tsconfig.json
ファイルを書き換えますtsconfig.json{ "compilerOptions": { "outDir": "build/lib", "module": "commonjs", "target": "es5", "lib": ["es5", "es6", "es7", "es2017", "dom"], "sourceMap": true, "allowJs": false, "jsx": "react", "moduleResolution": "node", "rootDirs": ["src", "stories"], "baseUrl": "src", "forceConsistentCasingInFileNames": true, "noImplicitReturns": true, "noImplicitThis": true, "noImplicitAny": true, "strictNullChecks": true, "suppressImplicitAnyIndexErrors": true, "noUnusedLocals": true, "declaration": true, "allowSyntheticDefaultImports": true, "experimentalDecorators": true, "emitDecoratorMetadata": true }, "include": ["src/**/*"], "exclude": ["node_modules", "build", "scripts"] }Storybookアドオン
Storybook単体ではスタイルガイドの機能としては不十分なので、アドオンを追加していきます。
アドオンの追加は基本的には以下の手順です。
アドオンのインストールを行いshellnpm i -D @storybook/{ アドオン名 }addons.jsファイルに以下コードを記述
.storybook/addons.jsimport '@storybook/{ アドオン名 }/register';addon-knobs
スタイルガイドの対象コンポーネントに
props
を渡して、コンポーネントの状態を変化させることができます。GUIで簡単に確認できるので、非エンジニアでもコンポーネントのデザインチェックを行うことができます。
コード一例import React from 'react'; import { withKnobs, text, boolean, select } from '@storybook/addon-knobs'; import List from '@material-ui/core/List'; import ListItem from '@material-ui/core/ListItem'; import Button from '@material-ui/core/Button'; import IconButton from '@material-ui/core/IconButton'; import StarBorderIcon from '@material-ui/icons/StarBorder'; import { storiesOf } from '@storybook/react'; const colorOptions: any = { primary: 'primary', secondary: 'secondary', inherit: 'inherit', default: 'default', }; const sizeOptions: any = { small: 'small', medium: 'medium', large: 'large', }; const ButtonComponent: React.FC = () => { return ( <List> <ListItem> <Button color={select('Color', colorOptions, colorOptions.primary)} size={select('Size', sizeOptions, sizeOptions.medium)} disabled={boolean('disabled', false)} > {text('Label', 'Menu Button')} </Button> </ListItem> <ListItem> <IconButton color={select('Color', colorOptions, colorOptions.primary)} > <StarBorderIcon /> </IconButton> </ListItem> </List> ); }; storiesOf('./Button', module) .addDecorator(withKnobs) .add('./Button', () => <ButtonComponent />);addon-actions
コード一例import React from 'react'; import { action } from '@storybook/addon-actions'; import List from '@material-ui/core/List'; import ListItem from '@material-ui/core/ListItem'; import Button from '@material-ui/core/Button'; import IconButton from '@material-ui/core/IconButton'; import StarBorderIcon from '@material-ui/icons/StarBorder'; import { storiesOf } from '@storybook/react'; const ButtonComponent: React.FC = () => { return ( <List> <ListItem> <Button onClick={action('button-click')} > Menu Button </Button> </ListItem> <ListItem> <IconButton onClick={action('icon-button-click')} > <StarBorderIcon /> </IconButton> </ListItem> </List> ); }; storiesOf('./Button', module) .add('./Button', () => <ButtonComponent />);addon-docs
addon-info
の上位互換のアドオンです。markdown
を使ったドキュメントを作ったり、MDX
形式でスタイルガイドを作成したりできるようです。
導入にはnpmモジュールのインストールの他に一手間かける必要があります。
まず、.storybook
配下にpresets.js
を作成し、以下コードを記述します。.storybook/presets.jsmodule.exports = ['@storybook/addon-docs/react/preset'];
mdx
を使いたい場合config.js
を書き換えます.storybook/config.jsconfigure(require.context('../stories', true, /\.stories\.(tsx|mdx)$/), module);以下のように
.mdx
形式ファイルはmarkdown
が使えるため、簡単にきれいなドキュメントを作成できます。storyコード一例(mdx使用)import { Meta, Story, Preview } from '@storybook/addon-docs/blocks'; import { ButtonComponent } from './Button'; //reactコンポーネントを読み込み <Meta title="MDX|ButtonComponent" component={ButtonComponent} /> # ButtonComponent With `MDX` we can define a story for `ButtonComponent` right in the middle of our markdown documentation. <Preview> <Story name="ButtonComponent"> <ButtonComponent /> </Story> </Preview> | TH | TH | | ---- | ---- | | TD | TD | | TD | TD |addon-storyshots
addon-storyshots
を使えば、jestと組合あせてStorybookに登録されているコンポーネントのテストを行うことができます。Storybookに登録されているコンポーネントに何かしらの変更を加えるとエラーとして検出され異常をすぐに検知することができます。
こちらもaddon-docs
同様、導入にはnpmモジュールのインストールの他に一手間かける必要があります。
ただ、今回はaddon.js
へのregister記述は必要ありません。まず、追加で以下のモジュールをインストールします。jestスナップショットを行うために必要です。
npm i -D require-context.macro react-test-renderer
次に
config.js
を書き換えます.storybook/config.jsimport { configure } from '@storybook/react'; import requireContext from 'require-context.macro'; // automatically import all files ending in *.stories.js const req = requireContext('../stories', true, /\.stories\.(tsx|mdx)$/); function loadStories() { req.keys().forEach(filename => req(filename)); } configure(loadStories, module);最後にjestが検知されるパス(おそらくデフォルトは
.src/
)にstoryshots.test.tsx
を作成し、以下のコードを記述します。src/storyshots.test.tsximport initStoryshots from '@storybook/addon-storyshots'; initStoryshots();jestテストを実行すると、コンポーネントテストが行われ、src配下
__snapshots__
フォルダ内にスナップショットが記録されます。yarn test PASS src/storyshots.test.tsx Storyshots ./Button ✓ ./Button (64ms) Test Suites: 1 passed, 1 total Tests: 1 passed, 1 total Snapshots: 1 passed, 1 total Time: 3.563s Ran all test suites.少しでも変更するとエラーになります。スタイルガイドに変更を加えたい場合は、
__snapshots__
を一度削除してjestテストを再度行うことで、変更したコンポーネントが正しいものとして登録されます。FAIL src/storyshots.test.tsx Storyshots ./Button ✕ ./Button (57ms) ● Storyshots › ./Button › ./Button expect(received).toMatchSnapshot() Snapshot name: `Storyshots ./Button ./Button 1` - Snapshot + Received @@ -23,11 +23,11 @@ type="button" > <span className="MuiButton-label" > - Menu Button + Menu But </span> </button> </li> <li className="MuiListItem-root MuiListItem-gutters" at match (node_modules/@storybook/addon-storyshots/dist/test-bodies.js:27:20) at node_modules/@storybook/addon-storyshots/dist/test-bodies.js:39:10 at Object.<anonymous> (node_modules/@storybook/addon-storyshots/dist/api/snapshotsTestsTemplate.js:44:33) › 1 snapshot failed. Snapshot Summary › 1 snapshot failed from 1 test suite. Inspect your code changes or press ` u` to update them. Test Suites: 1 failed, 1 total Tests: 1 failed, 1 total Snapshots: 1 failed, 1 total Time: 4.575s Ran all test suites.まとめ
プロトタイピングやスタイルガイド作成は正直面倒です。ですが、全体イメージ・根底ルールをしっかりと定めておくと、改修フェーズで圧倒的に手戻りが少なく楽をすることができます。また、「Storybookに乗せるためにReactのコードをきれいに書かなくては」という衝動にもかられ、コードを書いていく上でもガイドラインがあるとないとでは全く意識が変わってきます。私自身まだ手探り状態なところではありますが、今回の学びを業務にも活かしていこうと思います。
ちなみに今回プロトタイプで作った、写真共有Webブラウザアプリ
をReactで実装する過程を次回以降のアドベントカレンダーの投稿で記述するつもりです。