- 投稿日:2019-03-18T23:37:46+09:00
React を静的HTMLでレンダリング
https://ja.reactjs.org/docs/getting-started.html#react-for-beginners にあった、
https://www.taniarascia.com/getting-started-with-react/ を参考に、1個の静的htmlファイルでReactをレンダリングする。元にするjsxは、https://qiita.com/y_ohr/items/77d1a70dd6cbe4a8b365 で作成した内容。
index.htmlに全てべた書き
index.html<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Hello React!</title> <script src="https://unpkg.com/react@16/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <script src="https://unpkg.com/babel-standalone@6.26.0/babel.js"></script> </head> <body> <div id="root"></div> </body> </html> <script type="text/babel"> class Square extends React.Component { constructor(props) { super(props); this.handleChange = this.handleChange.bind(this); } handleChange(e) { this.props.onNumberChange(e.target.value); } render() { return ( <input type="text" value={this.props.number} className="square" onChange={this.handleChange} > </input> ); } } const xyData = [ { x: 0, y: 1 }, { x: 3, y: 4 }, { x: 6, y: 7 }, ]; class App extends React.Component { constructor(props) { super(props); this.state = { xyData }; } renderSquare(i, m) { return <Square number={i} onNumberChange={m} />; } toNumber(n) { return n * 1; } render() { const title = 'XY加算機'; const xyData = this.state.xyData.slice(); return ( <div> <div className="title">{title}</div> {xyData.map((value, i) => ( <div className="board-row"> {this.renderSquare(value.x, (e) => { xyData[i].x = e; this.setState({ xyData }); }) } + {this.renderSquare(value.y, (e) => { xyData[i].y = e; this.setState({ xyData }); }) } = <input value = {this.toNumber(value.x) + this.toNumber(value.y)} /> </div> ))} </div> ); } } ReactDOM.render(<App />, document.getElementById('root')) </script>見づらいのでスクリプトを分割
index.html<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Hello React!</title> <script src="https://unpkg.com/react@16/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <script src="https://unpkg.com/babel-standalone@6.26.0/babel.js"></script> </head> <body> <div id="root"></div> </body> </html> <script type="text/babel" src="./app.js"></script>app.jsclass Square extends React.Component { constructor(props) { super(props); this.handleChange = this.handleChange.bind(this); } handleChange(e) { this.props.onNumberChange(e.target.value); } render() { return ( <input type="text" value={this.props.number} className="square" onChange={this.handleChange} > </input> ); } } const xyData = [ { x: 0, y: 1 }, { x: 3, y: 4 }, { x: 6, y: 7 }, ]; class App extends React.Component { constructor(props) { super(props); this.state = { xyData }; } renderSquare(i, m) { return <Square number={i} onNumberChange={m} />; } toNumber(n) { return n * 1; } render() { const title = 'XY加算機'; const xyData = this.state.xyData.slice(); return ( <div> <div className="title">{title}</div> {xyData.map((value, i) => ( <div className="board-row"> {this.renderSquare(value.x, (e) => { xyData[i].x = e; this.setState({ xyData }); }) } + {this.renderSquare(value.y, (e) => { xyData[i].y = e; this.setState({ xyData }); }) } = <input value={this.toNumber(value.x) + this.toNumber(value.y)} /> </div> ))} </div> ); } } ReactDOM.render(<App />, document.getElementById('root'))感想
- create-react-appが色々インストールしているものは何か?
- 静的htmlによるレンダリングはnpm startとどう違う?
- stateを保持するコンポーネントと使うコンポーネントと更新するコンポーネントが混乱する。
以上
- 投稿日:2019-03-18T19:40:12+09:00
Webの仕事をしていない人が個人Webサービスを作ってみて得られた知見
自己紹介
Akahoriと申します。普段はIT業界と関係ない仕事をしていますが、今の仕事があまり面白くなく、
Webサービスを作ることにしました。Webサービスには無限の可能性があるように感じたためです。
最近の世の中のイケイケな会社は大体クラウドとかサービスやっています。
昔、数年SIerでWindows向け業務パッケージソフトを作っていたので基本的なIT知識はあります。2018年夏ぐらいから書籍を買って勉強をしていましたが、2019年1月にconnpassにて3monthsServiceという
三ヶ月でサービスを開発しようというイベント見つけて参加させてもらったのが開発のきっかけです。感謝!
本記事は、私のようにWebに詳しくない人に向けた内容で、Webエンジニアの皆様には一般的なことかと思われます。
間違っている内容やもっと良い取り組み方があれば教えてもらえると大変助かります。作ったサービス
EVENT MAP!という、connpassのイベントを地図検索できるサービスを作りました。
技術力の問題でいきなりマネタイズは難しいと考え、自分で使えるサービスであれば良いと考えたためです。
connpass公式サイトだと「東京都」までしか地域が絞れないため、行けないイベントが多いんですよね。
スタートアップの有名な人も、自分か、かなり親しい人が欲しいサービスは作るのに良いと言っています。初期表示場所は設定ボタンにて東京、大阪、愛知、福岡、座標未登録から選べるようにしました。
検索ワードなども時間短縮のため記録できるようにしています。動作環境・利用言語
フロントで多く使われており、サーバーサイドも書けるということでJavascriptをまず覚えたいと考えました。
その中で、新しめで書籍なども出ているライブラリとしてReactメインで開発することにしました。
Vue.jsなども迷いましたが、ReactはJavascriptを多く書くとのことで学習として応用が効きやすいと考えたためです。
Reactの勉強自体は開発時に始めたわけではなく、昨年に入門書を2冊読み、少し機能があるTODOアプリが作れるぐらいのレベルでした。
(当然のように、あまり理解していなかったことが後に判明します)クライアント側言語:React+Redux, Material-UI
サーバー側言語:Node.js (Expressフレームワーク)
サーバー(PaaS):heroku (+mongoDB)
エディタ:Visual Studio Code得られた知見
スムーズにいく部分でなく、やはり詰まったところから学べることが多いです。
デザイン調整はめちゃくちゃ難しい。最初にHTML/CSSを体系的に学んでおくべき。
CSSといえばmargin padding font-sizeなどの超基礎しか知らないレベルでした。displayによる違いも理解していませんでした。
さらにいきなりReactでMaterial-UIというCSSフレームワークを使ったことと、ReactのJSX記法による混乱もあり、
ページ数が極端に少ないサービスであるにも関わらず、体感上、総開発時間の3-4割の時間をデザイン調整に使ってしまっています。PC版がようやく出来たと思っても、IEで崩れたり、スマホ対応があったり、さらにスマホ毎に画面サイズは違います。
Chrome、IE11、iPhone XS、iPhone SE、iPadなど、それぞれまともに表示できるようになると別のが崩れたりしていました。
ブラウザの表示倍率が100%でない場合に起こる問題などもありました。これは見なかったことにして難を逃れました。またデザイン調整に入るのが早すぎたことも時間を取られた原因でした。作っていく内に使い勝手の悪さに自分で気づいたり、
予定していた機能が実は実装できなく削除するなどにより、途中からボタンが増えたり無くなったり移動したりしました。
中盤までは大まかな配置などの段階で留めておき、IEでパーツが別の所にお邪魔していても無視し機能が固まってから調整すべきでした。CSSは要素同士が影響し合うため、おまじないコピペで解決しないのが難しいところです。
最初に、浅くても体系的にHTML/CSSを学んでいれば開発時間を短縮できたかと思います。技術的な問題は英語で検索する方が早い
単純に英語と日本語での利用者数の問題もあり、日本語で結果が見つかっても古いバージョンでの解決方法、などということもしばしば。
広く一般的な問題や地域特有の問題以外は、最初から英語で検索した方が早いように感じました。
Chromeの翻訳で雰囲気を掴んで、崩れたところだけ原文を読みました。重要なのはコードなのでこれで十分でした。
日本語の記事で良いのがある場合は、コードの部分は英語であるため検索で引っかかるということもあります。面倒な作業は評価、利用者の多いライブラリで。しかし実現が難しいこともある
最初はGoogleで適当にライブラリを検索していましたが、適当に選んだものやはり使い勝手が良くないことが多かったです。
試すのにも時間はかかるため、人気のものから試すべきと学びました。また、日付を取り扱う定番ライブラリとしてMoment.jsというのがあり、とても便利なのですが、
これを知らなかったためJavascriptのDateオブジェクトで直接日付の取扱いを頑張ってしまっていました。
使い勝手悪いなと思う所はみんなが思っており、使いやすいライブラリが存在するかを早めに調べるべきでした。一方、react-google-mapsというReactのライブラリ経由にてGoogle Maps Javascript APIを利用しマップ部分を
描画していたのですが、最終的にはライブラリを用いずに直接APIを利用し実装しました。
理由としては、納得のいかない挙動や、ライブラリ経由では利用できないAPIがあったことです。
また、利用者もライブラリでは直接のAPIほど多くないために技術的な問題の解決もスムーズにはいきません。
用語で検索しても何も出てこない場合、私のような技術の理解が浅い人は厳しいです。
今回のAPIのような、そのものの利用者が非常に多く使い勝手が良いAPIであれば、直接叩くことを早めに検討すべきでした。デザインや機能改善以外にもやることは結構ある
想定以上にありました。私が気づいていないこともまだまだありそうです。教えて下さい!
SEO
Google Search Consoleの登録
Google Analyticsの登録
meta description、titleタグ等の設定
Lighthouseなどのツールによるチェックマーケティング
Twitterカード、OGPの設定
独自ドメイン取得法律の問題の検討
利用規約、プライバシーポリシーの整備
著作権の問題が生じる可能性のある箇所を再点検利便性向上
問合せフォームの設置(googleフォーム便利でした)
PWA対応
DBに対する適切なインデックスの設定
DB等のデータ量増加が今後問題になることは無いか検討
適切なコメントを入れておくなどソースコードの保守性向上
SSL対応
CDNの利用検討(無料範囲でも便利でした)セキュリティ
APIやサーバー、DB、サービスのアクセス許可、制限、保存手法などを見直す
Chromeのデベロッパーツールなどで不要なネットアクセスやコンソールログが無いか見直す
XSSなど広く知られたセキュリティの問題が無いか見直すサービスをどう見てもらうのかを考える必要がある
なんとなく100人ぐらいに見てもらえて20人ぐらいにたまに使ってもらえるのかと考えていました。
私がTwitterなどのSNSを今更始めたばかりで繋がりが少ないということもありますが、
まず、アクセスしてもらえませんでした。
作っても、見てすらもらえないのでは始まりません。上の方に貼ったURLをスルーしたそこのあなた、作ったのはこれです(涙)私のようにSNSをあまりやっていなかった場合、学習定着と、繋がりを広げることを兼ねてQiitaに記事を書く、LT登壇するなどアウトプットを増やすことも並行してやるべきだったと感じました。
友人が多い人でも、サービスの潜在顧客と層が異なるのであれば同一の問題を抱えるかもしれないので、早めに考えるべきかもしれません。
ツイートなどで広める場合、リリース時の見せ方も重要かと思いました。個人開発者のサービスリリース時のツイートを50人分集め分析した結果、私の中ではURLと同時に動いてる動画を貼るのがバズりやすいという結論に至りましたが、私はリリース後でしたので時既に遅しでした。ここは一つ、最初のリリースは無かったことに!この段落は公開2日後の時点で書いていますが、多くの人に見ていただいて感無量です。
「サービス/アプリを作ったらQiitaに記事を書く」ことの重要性はかなり高いと学びました。
今後も積極的に書かせてもらいます。コミュニティに参加すると開発が捗る
私が参加させてもらっている3monthsServiceのような、
サービス開発のイベント・コミュニティに参加したことで非常に開発が捗ったと感じています。
- 開発仲間ができます。
- 定期的に進捗を報告しなければということが、開発に対する後押しになります。
- どうしても解決できない問題を詳しい人に聞けるかもしれません。(何かお返ししましょう)
- 開発で得た知見などを共有できます。
- 定期的にお互いレビューを行うことで、UI/UX改善やセキュリティの問題など事前に解決できる可能性があります。
サービス開発はめちゃくちゃ楽しい!
最後になりますが、サービス開発はめちゃくちゃ楽しいです。想定より熱中できます。
特に中盤の、プログラムが動くようになってきたところが最高です。
勉強したい人、稼ぎたい人、就職や転職に役立てたい人、よければ開発しましょう!
- 投稿日:2019-03-18T10:50:25+09:00
全部 TypeSctipt で書こう!
こんにちは。
突然ですが、TypeSctipt って便利ですよね。私は今まで数年間 JavaScript のまま書いていました。
(TypeScript も知っていたが、なぜ変換させてまで別言語で書くの?と思っていた)半年前、異動先の部署で使われていた TypeScript を使うことに。
導入コストがそれなりにあるし、億劫な気分でした。ですが現在、 TypeScript にメロメロです。
TypeScript の何が良いのか
- JavaScript の拡張言語であり、 ECMAScript の実装に準拠している
- async/await や const/let など、 JavaScript の知識で書ける
- JavaScript なのに型の恩恵が受けられる
- 型の補完とか
- 存在しないプロパティへの書き込みに対する警告とか
- Visual Studio Code という TypeScript を正しく完璧に使うためのツールが無料
JavaScript という無法地帯に降り立った天使。それが TypeScript
![]()
TypeScript がチームの生産性を向上させた話
現在、私の開発チームはバックエンドエンジニアが私を含め3名とフロントエンドエンジニアが1名いますが、
私がフロントエンド (React.js) を書いたり、
フロントエンドエンジニアがバックエンド (Node.js) を書いたりしています。JavaScript より型が安全で補完も効くので手が出しやすく、
コードレビューもフレームワークや思想など、
本質的な議論になる事が多いです。少しずつそれぞれの範囲を超えて仕事できるようになってきており、
ボトルネックなタスクにリソースが集中できて効率的です。また、もう2名も元々 Java エンジニアでしたが、
チームにジョイン後1ヶ月もかからず新機能のコンポーネントを開発してくれました。
他言語からの開発の入りやすさも言うこと無しです。バッチ処理などのスクリプトも JavaScript の真骨頂。
もちろん TypeScript で書いています。もう Web サービスは全部 TypeScript で書こう!
- 投稿日:2019-03-18T08:54:17+09:00
Atoms作成のベストプラクティスを考える
はじめに
まだ色々と試作の段階ですがAtomicDesingにおけるAtomsのベストプラクティスを考えたいと思います。
React + styled-componentsを使用しています。ざっくりとした目標としては
- コンポーネントの使い回しが容易に行える
- コンポーネントのパターンに依存したスタイルが増えないような設計
ソース全文
import React from 'react'; import styled from 'styled-components'; import PropTypes from 'prop-types'; import { colors, radius } from '../../constants'; import getFontSize from '../../common/get-font-size'; const Wrapper = styled.button` display: inline-flex; align-items: center; justify-content: center; padding: 0 8px; height: 24px; position: relative; border-radius: ${radius['base']}; border: none; cursor: pointer; ${ props => getFontSize(props.fontSize) } ${ props => getButtonColor(props.buttonColor) } ${ props => getButtonBackgroundColor(props.backgroundColor) } ${ props => getButtonType(props.buttonType) } `; const Button = props => { return ( <Wrapper {...props} /> ) } // ボタンの文字色を設定 const getButtonColor = buttonColor => { if (buttonColor === 'lightGray') { return `color: ${colors['gray-100']}`; } else if (buttonColor === 'link') { return `color: ${colors['blue-800']}`; } else { return `color: ${colors['white']}`; // default } } // ボタンの背景職を設定 const getButtonBackgroundColor = backgroundColor => { if (backgroundColor === 'gray') { return `background-color: ${colors['gray-600']}`; } else if (backgroundColor === 'lightGray') { return `background-color: ${colors['gray-100']}`; } else if (backgroundColor === 'indigo') { return `background-color: ${colors['indigo-800']}`; } else { return `background-color: ${colors['green-600']}`; // default } } // ボタンの形を設定 const getButtonType = buttonType => { if (buttonType === 'mini') { return ` width: 12px; height: 12px; padding: 2px; font-size: 8px; font-weight: bold; ` } else if (buttonType === 'large') { return `height: 32px;` } else if (buttonType === 'noRadius') { return `border-radius: 0;` } else if (buttonType === 'addRight') { return `border-radius: ${radius['right']}` } } Button.propTypes = { buttoncolor: PropTypes.string, backgroundColor: PropTypes.string, fontSize: PropTypes.string, buttonType: PropTypes.string, }; Button.defaultProps = { fontSize: 'base', }; export default Button;
分解して解説していきますインポート
import React from 'react'; import styled from 'styled-components'; import PropTypes from 'prop-types'; import { colors, radius } from '../../constants'; import getFontSize from '../../common/get-font-size';諸々のインポートを行います。
以下の部分は定数ファイルとフォントサイズを返す関数になりますimport { colors, radius } from '../../constants'; import getFontSize from '../../common/get-font-size';コンポーネント本体
const Wrapper = styled.button` display: inline-flex; align-items: center; justify-content: center; padding: 0 8px; height: 24px; position: relative; border-radius: ${radius['base']}; border: none; cursor: pointer; ${ props => getFontSize(props.fontSize) } ${ props => getButtonColor(props.buttonColor) } ${ props => getButtonBackgroundColor(props.backgroundColor) } ${ props => getButtonType(props.buttonType) } `; const Button = props => { return ( <Wrapper {...props} /> ) }
${ props => getButtonColor(props.buttonColor) }
のようにpropsから関数に値を渡すことでボタンの背景色・文字色・形などの特定のスタイルを返します。
そうすることで、渡す値によってスタイルを自由に組み合わせることができます。スタイル設定
// ボタンの文字色を設定 const getButtonColor = buttonColor => { if (buttonColor === 'lightGray') { return `color: ${colors['gray-100']}`; } else if (buttonColor === 'link') { return `color: ${colors['blue-800']}`; } else { return `color: ${colors['white']}`; // default } } // ボタンの背景職を設定 const getButtonBackgroundColor = backgroundColor => { if (backgroundColor === 'gray') { return `background-color: ${colors['gray-600']}`; } else if (backgroundColor === 'lightGray') { return `background-color: ${colors['gray-100']}`; } else if (backgroundColor === 'indigo') { return `background-color: ${colors['indigo-800']}`; } else { return `background-color: ${colors['green-600']}`; // default } } // ボタンの形を設定 const getButtonType = buttonType => { if (buttonType === 'mini') { return ` width: 12px; height: 12px; padding: 2px; font-size: 8px; font-weight: bold; ` } else if (buttonType === 'large') { return `height: 32px;` } else if (buttonType === 'noRadius') { return `border-radius: 0;` } else if (buttonType === 'addRight') { return `border-radius: ${radius['right']}` } }スタイルを返す各種関数です。
特にpropsに設定された値がない場合はデフォルトの状態を返すようにすることで、コンポーネントを呼び出しが楽になります。フォントサイズは共通化していますが、色の指定などはコンポーネントごとに分けて作成しています。定数を全て使うこともできますが、あえて色を制限することで、実装者によって微妙な色の差異が出てしまうことを防ぐためです。
成果物
<div className="story-wrapper"> <div className="story-item"> <h2 className="story-caption">デフォルト</h2> <p><Button>Default</Button></p> </div> <div className="story-item"> <h2 className="story-caption">文字色</h2> <p><Button buttonColor="lightGray">lightGray</Button></p> <p><Button buttonColor="link">link</Button></p> </div> <div className="story-item"> <h2 className="story-caption">背景色</h2> <p><Button backgroundColor="gray">gray</Button></p> <p><Button backgroundColor="lightGray">lightGray</Button></p> <p><Button backgroundColor="indigo">indigo</Button></p> </div> <div className="story-item"> <h2 className="story-caption">タイプ</h2> <p><Button buttonType="mini">mini</Button></p> <p><Button buttonType="large">large</Button></p> <p><Button buttonType="noRadius">noRadius</Button></p> <p><Button buttonType="addRight">addRight</Button></p> </div> <div className="story-item"> <h2 className="story-caption">組み合わせ</h2> <p><Button backgroundColor="lightGray" buttonColor="link">lightGray link</Button></p> <p><Button backgroundColor="gray" buttonType="large">gray large</Button></p> <p><Button backgroundColor="indigo" buttonType="noRadius">indigo noRadius</Button></p> <p><Button buttonColor="lightGray" buttonType="addRight">lightGray addRight</Button></p> </div> </div>Storybook
Storybookのstorybook-notesなどのアドオンを使用し、propsで渡す値を記載することでソースコードを確認しなくても容易にコンポーネントを使いまわせるようにしておくと良いと思われます。