- 投稿日:2019-04-17T22:18:26+09:00
GitHub Awesomeレポジトリ内の各レポジトリのスター数を見える化する
GitHub AwesomeレポジトリのREADMEに含まれる各GitHubレポジトリのURLにスター数を表示する(一覧化する)ための必要最低限のWebアプリです。(注意:GitHub Tokenを利用しないと、GitHub APIの制約で約50~60個のGitHubレポジトリにしかスター数が表示されません)
https://playground-d4915.firebaseapp.com/
皆さんのGitHub Awesomeレポジトリ巡りが少しでも快適になれば幸いです
背景
GitHubにはプログラミング言語のお勧めまたは人気のライブラリ、フレームワーク、URL等をまとめてくれている
Awesomeレポジトリ
が数多く存在します。Awesomeレポジトリを活用することでフレームワークやライブラリの候補を洗い出す作業等を大幅に短縮できます。しかしAwesomeレポジトリは各分野のライブラリやフレームワークを対象としてまとめているため、Awesomeレポジトリによっては項目数が数百~数千に及ぶことがあります。このため一つ一つのページを開いてStar数を確認して優先度付けするような作業もかなり大変です。このような悩みを解決するために各GithubレポジトリのURLにスター数が表示するための最低限のWebアプリを実装して、どこでも使えるようにFirebase上に配置しています。
NOTE:
一番最初にReactを試すときに各種ReactコンポーネントとTypeScriptを試すために作ったものなので、コードもデザインはほぼ何も考えていません。特にスマホからだと非常に使いづらいですが、一応使うことはできます。WebアプリのURL
以下のURLからアクセスできます。
https://playground-d4915.firebaseapp.com/
使い方
画面上部にある入力欄に必要な情報を入力して
GET
ボタンをクリックします。
- URL欄にAwesomeのGithubレポジトリURLを入力する
- Token欄にGithubアカウントのGithubトークンを入力する
- 未入力の場合はGithubトークン無しで実行する
- トークン無しの場合、Github APIの制約によりGithubレポジトリ50個弱分のGithubレポジトリのスター数しか取得できない。詳細は注意事項の節を参照。
- 使い捨てのGithubトークンを使用することを推奨
- Top List Number欄に表示するTop Nの数字を入力する
- 結果が出た後に入力してTop Nの値を変更することも可能
クリックするとAwesomeページに含まれる各Github URL情報をGithub API経由で取得します。全ての取得が完了すると、結果として以下のものを表示します。(テーブルと棒グラフはReactコンポーネントの使い勝手を試すだけに入れてます)
- Top Nのテーブル
- Top Nの棒グラフ
- スター文字およびスター数を埋め込んだAwesomeページ
- リンク先がGithubレポジトリURLでない場合、スター数は表示されない
- Github APIの実行回数超過エラー等が発生した場合は、スター数に-1が表示される。
注意事項 & Githubトークンの設定方法
基本的にクライアントのブラウザ側で「各Githubレポジトリ情報をGithub API経由で取得する」ように実装しています。Githubトークン無しの場合は
1時間あたり50回
しかAPI呼び出しを行えないため、GithubレポジトリのURLが多いAwesomeレポジトリだと50件弱までしかスター数を取得できず使い物になりません。NOTE:
Github APIの呼び出し上限を超過すると、それ以降はRate LimitによりGithub APIの応答結果が403 Forbiddenとなります。このためGithubレポジトリのURLが多いAwesomeレポジトリの場合は、Githubトークンを入力することがほぼ必須となります。Githubトークンを使用する場合は
1時間あたり5000回
API呼び出しを行えます。GitHub「Personal access tokens」の設定方法
Githubトークンを入力するのに抵抗がある方もいると思います。このためGithubトークンは使い捨てのものを作成して使用することをお勧めします。
ソースコード置き場
ソースコードは下記URLに配置しています。改造、流用、再配布などは自由にしていただいて構いません。Githubレポジトリは一時的な作業用にしか使っていませんが、極力削除しないようにします。
https://github.com/yoichiwo7/playground/tree/master/awesome-star/awesome-star-react
- 投稿日:2019-04-17T22:03:49+09:00
入門 React:簡単なまとめ
dapps開発を行なっており、フロントエンドはReactで開発することになったのでReactを勉強します。
ちなみにプログラミングに関してはRailsを少しできるくらいで全くの素人です。
勉強した内容に関して簡単にまとめたいと思います。Reactとは
2013年、Facebookが開発した、Webアプリの User Interface を構築するための Java Script ライブラリです。
仮想DOMなどを利用して余計な機能を排除し、View部分に特化しています。ソースコード
https://github.com/backstopmedia/bleeding-edge-sample-app
JSX
JSXとは(Java Script XML)
ReactのコンポーネントないでHTMLのような可読性の高く記述できる構文です
メリット:よく知られている、意味的にわかりやすい、構造の可視化コンポーネント
Reactの中心概念です。
基本的な書き方sample.jsclass diver extends Component { render() { return ( <div> <p>Hello world</p> </div> ); } }JSXとHTMLの違い
JSXとHTMLは基本的に同じですが若干異なるところがあります。
・HTMLの
class
は、JSXではclassName
・属性値を{}で括ることにより動的な属性値を記述できます
var classId = this.props.id ... <div class = {classId}>...</div>・条件分岐は
if
else
などではできない。・三項演算子
・変数に値を代入し参照する
・条件文を別の関数として呼び出し
・&&
といったものを利用します・三項演算子を使った例
sample.js{ this.state.loading ? <div id="loader"><p>Loading...</p></div> : <p>Done!</p> }・
key
ref
dangerouslySetInnerHTML
といった属性があるrender() { return ( <div> <input ref="textInput" ... /></input> </div> ); }この
ref
の設定により、{this.refs.textInput}で参照できるようになっています。・スタイルはキャメルケースで参照
<div style={styles}> <p>Hello world</p> </div> var styles= { width: 350px, margin-bottom: 10px, }コンポーネントのライフサイクル
コンポーネントは作成時、作成後、破棄時の3つのイベントで処理を登録する手段があります。
データフロー
Reactでのデータの流れは基本的に親から子への一方通行です
そして、props
とstate
の2つで、データの流れは扱えます。props
propTypes
データをバインディングできます
getDefaultProps
state
コンポーネントの内部状態を示すものです。
stateの更新
replaceState
とsetState
の2種類ありますが、setState
が使いやすいのでsetState
を主に使います。this.setState({ update: ---- })イベントの処理
ReactのイベントはJavaScriptのイベントと基本的に同じです
例えば、
・MouseEvent:ユーザーがクリックした時の通知
・change:要素の内容が変わった場合の通知SystematicEvent
sample.jsclass diver extends Component { handleCreate (event) => { this.setState({ update: event.target.value }) } render() { return ( <div> <input onChange={this.handleCrate} /> </div> ); } }コンポーネントの合成
Mixin
複数のコンポーネント間で共有できるメソッドを定義できます。
DOM操作
どうしてもDOMにアクセスしたい場合は、ref属性を設定することで特定のコンポーネントにアクセスできます。
フォーム
Uncontrolled Component
複雑なフォームの作成に向いており、直接DOMノードへアクセスします。
そのため特殊なパターンであると言えます。smaple.jsclass UncontrolledComponent extend component { render () { return ( <input type="text" defaultValue="Hello world" />; ) } }このように、
UncontrolledComponent
のコンポーネントとは関係なく、Input
は独自の値を保有しています。smaple.jsclass UncontrolledComponent extend component { submitHandler: function (event) { event.preventDefault(); var hello = React.findDOMNode(this.refs.hello).value; } render () { return ( <form onSubmit={this.submitHandler}> <input type="text" defaultValue="Hello world" ref="hello" />; ) } }
Input
にref
属性を記述することによって、this.refs
でアクセス可能になっています。Controlled component
下記の
Input
はstate
により保持されているのでControlled component
と言えます。smaple.jsclass ControlledComponent extend component { handleChange = e => { this.setState({ hello: e.target.value}) } submitHandler = e => { event.preventDefault(); .... } render () { return ( <form onSubmit={this.submitHandler}> <input type="text" defaultValue="Hello world" value={this.state.hello} onChange={this.handleChange} />; </form> ) } }ラベル
フォームが何を意味しているかを、ユーザーに伝えるため利用します。
Sampele.js<label htmlFor="name">名前</label>select
sample.js<select value={this.state.hoge} onChange={this.handleChange}> <option value="A">選択肢A</option> <option value="B">選択肢B</option> <option value="C">選択肢C</option> </select>Checkbox
smaple.jsclass SampleCheckBox extend component { constructor(props) { super(props) this.state = { checked: true, } handleChange = e => { this.setState({ checked: e.target.checked}) } submitHandler = e => { event.preventDefault(); console.log("checked:", this.state.checked) .... } render () { return ( <form onSubmit={this.submitHandler}> <input type="checkbox" checked={this.state.checked} onChange={this.handleChange} />; </form> ) } }フォーカス
Autodocus
を使うと、ユーザーがブラウザを開いた時に、
クリックする必要なくform
を入力できるようになります。input.js<input type="text" autoFocus={true} />ユーザビリティー
ユーザビリティーの向上には下記の5つを考えると良いです。
ユーザーのやることが明確である
placeholder
、label
等を使って何をやれば良いのか明確にするユーザーの入力に即座に応答する
処理に時間がかかる場合、「ロード中」と出すだけでもユーザーの忍耐力は変化する
予測可能であること
アクセシビリティー
マウスだけ、タッチだけ、といった一定の制約下でテストを行ってみる
入力項目をなるべく少なくする
オートコンプリートなどを利用して、「たくさん入力する必要がある」とユーザーに感じさせない
Java Script
アロー関数、スプレッド構文、に関してはReactを勉強する際に覚えておくよいJavaScriptの概念になります。
アロー関数
function
を省略して書くことができる// 一般的な関数 var func = function(str) { console.log(str); } // アロー関数 var func = (str) => { console.log(str); }スプレッド構文
Sample.js// 従来の書き方 function myFunction(x, y, z) { } var args = [0, 1, 2]; myFunction.apply(null, args); // スプレッド構文 function myFunction(x, y, z) { } var args = [0, 1, 2]; myFunction(...args);参考サイト
JavascriptがわかってないとReactもわからないことが多くなるため
ES2015(ES6) 入門イベントリスナー
イベントパンドラ
DOMノード
- 投稿日:2019-04-17T21:48:36+09:00
React-Day-Pickerのスタイルを変える方法
日付選択機能が拡張しやすそうというで理由でblueprintというUI Toolkitを使っているのだが、実際に使ってみて見た目を変えたいなと思った所、結構癖があったのでメモしていく。
blueprintのDatePickerはReact-Day-Pickerのラッパー的なもの
blueprintのDatePickerはReact-Day-Pickerをベースにしていて、プロパティ経由で簡単にReact-Day-Pickerのプロパティを指定することができる。
ので、見た目を変えるときはReact-Day-Pickerの機能を使う必要が出てくる。
export function Test() { const customProps = { ... } //React-Day-Pickerの設定 return <DatePicker dayPickerProps={customProps} /> }スタイルを変えるときに取ることが出来る方法は以下のものがある。
ここで注意するのが、日にちに対するスタイルの指定とUI全体のスタイルの指定の二種類ある
(classNameも用意されている)カレンダーの日にちのスタイルを変更する
- modifiers
- modifiersStyles
DayPicker全体のスタイルを変更する
- classNames
日にちのスタイルを変更する
React-Day-Pickerではある日にちをいじりたいときはmodifiersプロパティを使って指定する形をとっている。
その際グループ化したい日にちのパターンとその名前という形で設定していく。
設定したグループの日にちには
DayPicker-Day--<グループ名>
という名前のCSSクラスの名前が与えられるので
それに対してスタイルを設定すると好きな見た目に変更することが出来る。もちろん自動生成されたCSSクラス名をCSSファイルに書かないといけない訳ではなく、
modifiersStyles
にグループ名をキーをとしたinline-Styleを設定すればいい。Matching days with modifiersにあるサンプルコードをちょっと変えたもの。
import React from 'react'; import DayPicker from 'react-day-picker'; import 'react-day-picker/lib/style.css'; const birthdayStyle = `.DayPicker-Day--highlighted { background-color: orange; color: white; }`; const modifiers = { highlighted: new Date(2018, 8, 19), }; const modifiersStyles = { highlighted: { color: '#FF0000' } } export default function MyBirthday() { return ( <div> <style>{birthdayStyle}</style> <DayPicker modifiers={modifiers} modifiersStyles={modifiersStyles} month={new Date(2018, 8)} /> </div> ); }日にちの指定の仕方
グループを作る際の日にちの指定には以下の種類があるので適当に使い分ける。
グループは複数指定でき、ある日にちが二つ以上のグループにあるときはその全てが適応される。
- from/toキー この二つに与えたDateオブジェクトの範囲内の日にちをグループ化する
- beforeキー 与えた日にちより前のものをグループ化する
- afterキー 与えた日にちより後のものをグループ化する
- daysOfWeek 指定した曜日でグループ化する。曜日は0から6の範囲を取り、それぞれ日曜から土曜に対応している。配列で渡すと複数の曜日を指定できる。
- function(day: Date):boolean グループ化する日にちのときはtrueを返すDateオブジェクトを受け取る関数
const from_to = [ from: new Date(2018, 8, 19), to: new Date(2018, 9, 19), ] const before_after = { after: new Date(2018, 9, 1), before: new Date(2018, 10, 1) } const daysOfWeek = { daysOfWeek: [0] // 日曜日 } const func = (day) => { return day.getDate() % 2 === 0} export default function Grouping() { return ( <div> <style>{birthdayStyle}</style> <DayPicker modifiers={[from_to, before_after, daysOfWeek]} /> </div> ); }用意されているグループ
ちなみにtodayとoutsideが予め用意されており、それぞれ今日の日にちと現在の月以外の日にちが対象になる。
イベントとの組み合わせ
グループはDayPickerのイベントが起きたときに日にちを識別する目的にも使うことが出来る。
グループ情報を参照することが出来るイベントにはmodifiersがオブジェクトとして引数に渡されていて、
そのオブジェクトには所属しているグループの名前をboolean型として持っている。//ドキュメントから拝借 import 'react-day-picker/lib/style.css'; export default class EventHandlers extends React.Component { constructor(props) { super(props); this.handleDayClick = this.handleDayClick.bind(this); this.handleDayMouseEnter = this.handleDayMouseEnter.bind(this); } handleDayMouseEnter(day, { firstOfMonth }) { if (firstOfMonth) { // Do something when the first day of month has been mouse-entered } } handleDayClick(day, { sunday, disabled }) { if (sunday) { window.alert('Sunday has been clicked'); } if (disabled) { window.alert('This day is disabled'); } } render() { return ( <DayPicker disabledDays={new Date()} modifiers={{ sunday: day => day.getDay() === 0, firstOfMonth: day => day.getDate() === 1, }} onDayClick={this.handleDayClick} onDayMouseEnter={this.handleDayMouseEnter} /> ); } }と、かなり汎用性があるものになっている。
DayPicker全体のスタイルを変更するときはclassNames用のテンプレートを使おう
日にちについてはかなり柔軟なカスタマイズが出来るようになっているが、
それ以外の例えばヘッダー部分とかの背景色を変更したいときはclassNamesプロパティを使う。classNamesにはDayPickerで使われる要素全てにCSSを指定する形になっている。
各要素には使用するCSSクラスを指定するのだが、要素の数は結構あるので公式から用意されているテンプレートを書き換えるのがいいと思う。
テンプレートはこちら react-day-picker/src/classNames.js
テンプレートのインターフェイスは
import {ClassNames} from 'react-day-picker'
からインポート出来る。function makeClassNames(config) { const DEFAULT = { container: 'DayPicker', wrapper: 'DayPicker-wrapper', interactionDisabled: 'DayPicker--interactionDisabled', months: 'DayPicker-Months', month: 'DayPicker-Month', navBar: 'DayPicker-NavBar', navButtonPrev: 'DayPicker-NavButton DayPicker-NavButton--prev', navButtonNext: 'DayPicker-NavButton DayPicker-NavButton--next', navButtonInteractionDisabled: 'DayPicker-NavButton--interactionDisabled', caption: 'DayPicker-Caption', weekdays: 'DayPicker-Weekdays', weekdaysRow: 'DayPicker-WeekdaysRow', weekday: 'DayPicker-Weekday', body: 'DayPicker-Body', week: 'DayPicker-Week', weekNumber: 'DayPicker-WeekNumber', day: 'DayPicker-Day', footer: 'DayPicker-Footer', todayButton: 'DayPicker-TodayButton', // default modifiers today: 'today', selected: 'selected', disabled: 'disabled', outside: 'outside', }; return Object.assign({}, DEFAULT, config) } export default function CustomClassNames() { // const classNames = makeClassNames({ container: 'changeBackground' }) return ( <DayPicker classNames={ styles } modifiers={{ [styles.birthday]: new Date(2018, 8, 19) }} /> ); }ちなみにデフォルトで設定されているクラスを完全に上書きしてしまうとレイアウトが崩れたので、次のように追記する形にしたほうがいいと思う。
指定したクラス名はそのまま設定されるようなので、
classnames
パッケージとか利用したら便利。const custom = { caption: classnames('DayPicker-Caption', 'appendStyles') }もちろんCSSModuleも使える
ので、好きな方法でスタイルをカスタマイズすることが出来る。
かなり拡張性が高いパッケージになっていて、日時選択にはこれが一番融通がきくのではないかなと。
おすすめのパッケージです。
- 投稿日:2019-04-17T17:23:39+09:00
React.useEffectで非同期処理をする場合の注意点2つ
はじめに
React 16.8から導入されたhooksにはuseEffectがあります。
詳細は公式サイトをまず参照しましょう。
useEffectを使うと、コンポーネントのレンダリングとは別に処理を書くことができます。useEffectでしばしば非同期処理を書くことがあります。例えば、サーバからのデータ取得の処理などがあります。
以下では、useEffectで非同期処理を書く場合の注意点を2つ紹介します。ケースによっては注意点はこの2つだけではない可能性が高いので、ご留意ください。
promiseを返さない
useEffectに渡す関数の戻り値はcleanup関数です。
useEffect(() => { console.log('side effect!'); const cleanup = () => { console.log('cleanup!'); }; return cleanup; }, []);cleanup関数は次のeffectが呼ばれる前やアンマウントする場合に呼ばれます。(depsが
[]
なのでこの例では後者のみ)よって、下記は間違いです。
useEffect(async () => { await new Promise(r => setTimeout(r, 1000)); console.log('side effect!'); }, []);このコードはcleanup関数の代わりにpromiseを返してしまっています。
正しくは、下記のようにします。const sleep = ms => new Promise(r => setTimeout(r, ms)); useEffect(() => { const f = async () => { await new Promise(r => setTimeout(r, 1000)); console.log('side effect!'); }; f(); }, []);アンマウントのフラグを持つ
非同期処理を書く場合、コンポーネントが削除された後にコールバックが呼ばれる場合があります。この時、コンポーネントのステートを変更しようとするとワーニングがでます。
const [count, setCount] = useState(0); useEffect(() => { const f = async () => { await new Promise(r => setTimeout(r, 1000)); setCount(c => c + 1); }; f(); }, []);これを回避するには次のようにアンマウントのフラグを持ちます。
const [count, setCount] = useState(0); useEffect(() => { let unmounted = false; const f = async () => { await new Promise(r => setTimeout(r, 1000)); if (!unmounted) { setCount(c => c + 1); } }; f(); const cleanup = () => { unmounted = true; }; return cleanup; }, []);おわりに
React HooksのuseEffectについて非同期処理を使う場合のよくあるケースの注意点について紹介しました。React Hooksはまだベストプラクティスが溜まっていないため、今後違う方法が主流になる可能性はある点についてはご注意ください。
- 投稿日:2019-04-17T09:00:43+09:00
SSRの時間計測方法(Nextjs)
Nextjsはlibの中にrenderToStringが入っていて純粋にrenderToStringのみの計測ができなそうなので、以下のような感じで妥協するしかなさそう。
const serverTiming = require('server-timing') const ssrTiming = async ({ req, res, pagePath, queryParams }) => { res.startTime('ssr', 'SSR') const html = await app.renderToHTML(req, res, pagePath, queryParams) res.endTime('ssr') res.send(html) } app.prepare() .then(() => { const server = express() server.use(serverTiming()) // SSRの時間を計測したいパス server.get('/', (req, res) => { return ssrTiming({ req, res, pagePath: '/' })) } server.get('*', (req, res) => { return handle(req, res) }) server.listen(port, (err) => { if (err) throw err console.log('> Ready on http://localhost:' + port) }) }) .catch((ex) => { console.error(ex.stack) process.exit(1) })
- 投稿日:2019-04-17T01:29:01+09:00
Reactでpropsを渡すときに使う「...」ドット3つ
render() { const obj = { a:1, b:2 } return ( <Component {...obj} /> ) }なんか気持ち悪いなと思ったらjsx(React.jsでhtmlをつくること)特有の書き方らしい。
以下のようにして書くのと同じこと。render() { const obj = { a:1, b:2 } return ( <Component a={1} b={2} /> ) }ひとつひとつpropsを定義してあげて渡すか、
オブジェクトを展開してあげてまとめて渡すかの違い。