前回はアイコンやテキスト情報を表示しましたが、色を直接指定することができませんでした。primary
やerror
など意味を示す物でしたよね。今回はデフォルトで定義されている色などを変更するテーマ機能を触ってみます。
React
はじめてのReact #29 「CSSフレームワークを導入する」Material-UI アイコンと文字スタイル編
Material-UIシリーズ第三回は文字のスタイルをあれこれいじってみたいと思います。
SVGアイコンを表示したり、テキストを様々な形で表示します。
はじめてのReact #28 「CSSフレームワークを導入する」Material-UI グリッド編
前回はMaterial-UIのインストールと基本的な利用方法について取り上げました。今回は画面のレイアウトを行う際に利用するグリッドシステムです。
この手のCSSフレームワークの醍醐味の一つはグリッドが用意されていることですね。最近はflexbox
が使えるようになってずいぶん楽になりましたが、細かい制御をやってくれるので中々重宝するんですよね。
続きを読む
はじめてのReact #27 「CSSフレームワークを導入する」Material-UI インストール編
Reactでは通常のWebサイトと同様、自由自在にCSSを記述し反映することができるわけですが、ゼロから書き始めるのは個人的に正直ダルい。そんなときにタグにクラス名を適当に指定すればチャチャッといい感じに表示してくれるCSSフレームワークを導入したいと思います。
今回はよく名前を見かけるMaterial-UIを使ってみることにします。長いものには巻かれろ精神。
はじめてのReact #26 「ルーティングに対応する」設定をJSONにまとめる編 react-router@v5
これまでルーティング関連の記事では以下のような内容を取り上げてきました。
今までは以下のように直接<Route>
を書いてルーティングの定義を行ってきましたが、今回はこれらの設定をJSONなどで定義し、いつでも外部のファイルに出せるようにします。
<!-- befor -->
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/auth" component={Auth} />
<Route path="/area/:cd" component={Meisan} />
</Switch>
このままでも動くんですけどね。ロジックと設定は分離して置いた方がメンテしやすくなりますからね。
はじめてのReact #25 「ルーティングに対応する」認証とリダイレクト編 react-router@v5
前々回では基本的なReactRouterの使い方を、前回でURLの一部をパラメーターとして受け取ってみました。
今回はユーザーの状態に合わせてページの出し分けを行います。
具体的には
- 認証済みのユーザーにだけページを表示
- 未認証のユーザーにはログインページを表示
という仕様になります。
続きを読む
はじめてのReact #24 「ルーティングに対応する」URLパラメーター編 react-router@v5
前回はReact Routerの基本的な機能を利用し簡単な図鑑アプリを作成しました。
今回はリクエストを受けたURLの一部をパラメーターとして受け取ってみます。
例えばブログやTwitterのようなアプリで特定のIDの記事を表示したい場合/posts/view/123
といった形式のURLにアクセスするとします。ここで問題になるのは1000個の記事があった場合、1000個の<Route>
を定義する必要が出てくるのかという点ですね。こういった場合に特定のパターンのURLは一部の文字列をパラメーターとして設定することができます。
はじめてのReact #23 「ルーティングに対応する」基本編 react-router@v5
React Routerは雑に言うとリクエストされたURLのパスと、ReactのComponentを紐付けてくれる便利なモジュールです。
例えば /foo
にアクセスされたら FooComponent
を、/bar
にアクセスされたらBarComponent
を実行することができるようになります。
今回は3月21日に登場したばかりのReact Router v5を触ってみます。本来はv4.4として出す予定だったそうですがReact 16との互換性が大きく改善されたとのことでメジャーバージョンアップの運びとなったとのこと。使い方もv4系とあまり変わらないようですね。
はじめてのReact #22「ToDoアプリを作る」 後編
3回に渡ってお送りしたToDoアプリ開発も最終回。今回はAjaxを利用しデータをサーバに保存してみます。
Propsのデータ型をチェック
以前取り上げたPropsのデータ型のチェックを導入しておきます。
プロジェクトも運用段階に入りComponentがどこからどのように呼び出されるか、収集がつかなくなったとしても呼び出し方さえ守ってもらえれば何とかなったりするものです(それが良いかはさて置き)。また誤った利用方法をするとテスト段階でエラーを明示的に出してくれるのもありがたいものです。
src/header.js
import PropTypes from 'prop-types';
// <Header>
// React ToDo
// </Header>
Header.propTypes = {
children: PropTypes.string.isRequired
};
src/todocreate.js
import PropTypes from 'prop-types';
// <ToDoCreate onClick={this.handleClick} />
ToDoCreate.propTypes = {
onClick: PropTypes.func.isRequired
};
src/todolist.js
import PropTypes from 'prop-types';
// <ToDoList data={this.state.todo} remove={this.handleRemove}/>
ToDoList.propTypes = {
data: PropTypes.array.isRequired,
remove: PropTypes.func.isRequired
};
src/todoitem.js
import PropTypes from 'prop-types';
// <ToDoItem key={i.id} item={i} remove={this.props.remove} />
ToDoItem.propTypes ={
item: PropTypes.object.isRequired,
remove: PropTypes.func.isRequired
};
データをサーバ側で管理する
APIサーバを用意
Reactから話がずれますが、学習用に保存や取り出しを行うAPIサーバをNode.jsで準備します。かなり簡易的な物なので本番投入はしないでください。しないとは思いますがw
まずは適当な名前のディレクトリを作成しカレントディレクトリを別の場所に移します。今のプロジェクトは全く別の場所に作成してください。その後簡単にHTTPサーバを作成できるexpressを入れます。
$ mkdir apiserve; cd apiserve
$ npm install express
詳細は説明しませんが、以下のスクリプトをexpressをインストールしたディレクトリに適当な名前で保存します。ここではserve.js
としました。
続きを読む
はじめてのReact #21「ToDoアプリを作る」 中編
前回に引き続き今回もToDoアプリを作っていきます。目標としてはフォームの使い勝手を向上させつつToDoの削除に対応するところまでとなります。
フォームを改良する
Submitイベントに対応
現状、登録フォームのテキストボックスに内容を入力しエンターキーを押した瞬間、再読込されてしまいます。これを防ぐには、formタグにonSubmit
イベントを定義してあげればOK。今回はエンターキーを押すと確認用のダイアログを表示し、OKボタンが押されれば追加処理を行う形に変更しました。
src/todocreate.js
を以下のように変更します。
import React, { Component } from 'react';
class ToDoCreate extends Component {
constructor(props){
super(props);
this.state = {
newtodo: ""
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e){
this.setState({
newtodo: e.target.value
});
}
handleSubmit(e){
let newtodo = this.state.newtodo;
if(newtodo !== "" && window.confirm('本当に登録しますか?')){
this.props.onClick(newtodo);
this.setState({newtodo:""});
}
e.preventDefault();
}
render(){
return(
<form onSubmit={this.handleSubmit}>
<input type="text" value={this.state.newtodo} onChange={this.handleChange}/>
<button>追加</button>
</form>
);
}
}
export default ToDoCreate;
注意すべき点としてはconfirm()
ではなく、window.confirm()
とする必要があるところでしょうか。
Validationを行う
もう一つの問題点として、テキストボックスが空でも登録されている点ですね。これも直して置きます。src/todocreate.js
のhandleSubmit()を以下のように変更しました。空文字列または2文字未満であれば何もしません。
handleSubmit(e){
e.preventDefault();
let newtodo = this.state.newtodo;
if(newtodo === "" || newtodo.length < 2){
return(false);
}
if(newtodo !== "" && window.confirm('本当に登録しますか?')){
this.props.onClick(newtodo);
this.setState({newtodo:""});
}
}
テキストボックスにfocusする
ToDoを入力する際にわざわざテキストボックスをクリックするのも面倒なので、ページが読み込まれたと同時にfocusをしてあげます。src/todocreate.js
を以下のように変更します。
import ReactDOM from 'react-dom'; //追加
class ToDoCreate extends Component {
// (snip)
componentDidMount(){
ReactDOM.findDOMNode(this.refs.newtodo).focus();
}
// (snip)
render(){
return(
<form onSubmit={this.handleSubmit}>
<input type="text" ref="newtodo" value={this.state.newtodo} onChange={this.handleChange}/>
<button>追加</button>
</form>
);
}
}
上記は変更した部分だけを抜き出しています。
まずReactDOMの機能を利用しますので新たにimportしました。
componentDidMount()
はLifeCycleの機能。ComponentがDOMツリーに追加された瞬間に呼び出されます。ここで単純にfocus()メソッドを実行してあげればよいのですが、問題はどうやってテキストボックスを特定するかです。
今回はテキストボックスに<input type="text" ref="newtodo">
といった形でref
属性を追加しました。この属性をつけておくとReactから簡単に参照することができるようになります。この場合だとthis.ref.newtodo
ですね。
ReactDOM.findDOMNode()は最終的にDOMオブジェクトを返却しますので、これでテキストボックスを検索し、戻り値のDOMオブジェクトに対してfocus()を実行しているといます。
Lifecycleについては過去の記事を参照してください。
はじめてのReact #20「ToDoアプリを作る」 前編
前回準備した環境を使って、早速Webアプリを作ってみたいと思います。こういうときはToDoアプリを作るのが伝統となっていますので、それに習いますw
なお、本来であればテストコードを書きながら進めるべきだとは思いますが、今回は割愛しております。
準備編
プロジェクトの作成
rtodoという名前でプロジェクトを新規作成しました。rはReactで作るぞという意思表示で特に意味はありませんw 好きな名称をつけてください。
$ create-react-app rtodo
Gitリポジトリの準備
GitHubにもrtodo
という名前でリポジトリを準備しました。まずはこいつにgit push
します。
https://github.com/katsube/rtodo
$ git remote add origin git@github.com:katsube/rtodo.git
$ git push -u origin master
Componentを作ってみる
新しいComponentを作る
まずは腕鳴らしに簡単なComponentを用意してみます。src/header.js
というファイルを作成し、その中に以下のコードを記述します。render()
でタグを描画しているだけですね。h1の中はprops.childrenでもらった文字列をそのまま出しています。
import React, { Component } from 'react';
class Header extends Component {
render() {
return(
<header>
<h1>{this.props.children}</h1>
</header>
);
}
}
export default Header;
最後のexport文を忘れないように気をつけてください。これを記述することで他のファイルからこのComponentを利用することができるようになります。
子供の要素にアクセスする方法(this.props.children
)については過去の記事を参照してください。
はじめてのReact #19「開発環境を準備する」create-react-app編
ここまでご紹介してきたサンプルは学習やちょっとした検証には使えるのですが、実際に本番環境で動かすのには向いていません。というわけで今回は本番環境で動かすコードを作成するための開発環境を準備してみたいと思います。
Reactの開発環境
Node.jsのインストール
まず最初にNode.jsを入れる必要があるのですが、アップデートに対応しやすくするためバージョン切り替えが手軽に行えるツールをインストールした上でNode.jsの最新版を入れます。
MacやLinuxならnodebrew
Windowsならnodist
今回は以下のバージョンで構築を開始します。npmはNodejs用のパッケージマネージャーで、これを使って様々な便利ライブラリやツールをインストールすることができます。
$ node --version
v11.7.0
$ npm --version
6.5.0
create-react-appのインストール
Reactの開発環境をゼロから作ろうとすると中々に面倒なのですが、コマンド一発で必要な物を一式揃えてくれる便利ツールがfacebookより公式に提供されているので今回はこちらを利用してみます。
では先ほどインストールしたnpmコマンドを利用してこのcreate-react-app
を入れます。npmを利用するとコマンド一発で入ります。
$ npm install -g create-react-app
今回は以下のバージョンが入りました。
$ create-react-app --version
2.1.3
はじめてのReact #18「Ajaxでデータ取得」
昨今のWebアプリではWebAPI(RESTful API等)をAjaxなどで叩きデータを取得する、もしくはデータを保存するといった行為を日常的に行っているわけですが、今回はAjaxでデータ取得し表示するまでに挑戦してみます。
MonsterView Component
とあるRPGのモンスターの一覧が記録されたJSONファイルをAjaxで取得し、そのままReactで表示するサンプルです。公式ドキュメントの例をちょろっといじったものになります。
サンプル
データファイルです。実際にはサーバ側で動的に出力することが多いと思いますが、今回は静的なファイルで試します。ファイル名はdata.json
。
{
"monsters": [
{ "id": 1, "name": "スライム", "hp": 10 },
{ "id": 2, "name": "ドラキー", "hp": 12 },
{ "id": 3, "name": "おおありくい", "hp": 36 }
]
}
実際の処理を行うHTMLです。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>MonsterView</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>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
class MonsterView extends React.Component {
constructor(props) {
super(props);
this.state ={
isLoaded: false,
error: null,
monsters: []
}
}
componentDidMount() {
fetch("https://s3-us-west-2.amazonaws.com/blog.katsubemakito.net/static/react1st/18/data.json")
.then(res => res.json())
.then(
(result) => {
this.setState({
isLoaded: true,
monsters: result.monsters
});
},
(error) => {
this.setState({
isLoaded: true,
error: error
});
}
)
}
render() {
if (this.state.error) {
return <div>Error: {this.state.error.message}</div>;
}
else if ( !this.state.isLoaded ) {
return <div>Loading...</div>;
}
else {
return (
<ul>
{this.state.monsters.map( monster => (
<li key={monster.id}>
{monster.name} {monster.hp}
</li>
))}
</ul>
);
}
}
}
ReactDOM.render(
<MonsterView />,
document.getElementById('root')
);
</script>
</body>
</html>
はじめてのReact #17「CSSを適用する」
これまで何の前触れもなくチラッと出てきたComponentにCSSを適用する方法について、いよいよ解説したいと思います。まぁブログの構成(順番)を間違えてるだけなんですけどねw もっと早く取り上げるべきだったw
ダイアログ Component
Component名は前回と同じですが、今回はボタンをクリックする度に文字色が変化するサンプルにしてみました。
サンプル
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Dialog</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>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
<style type="text/css">
.dialog {
border: 1px solid gray;
background-color: beige;
text-align: center;
}
</style>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
class Dialog extends React.Component {
constructor(props) {
super(props);
this.state ={
i: 0
}
this.handleClick = this.handleClick.bind(this);
}
handleClick(){
this.setState({
i: this.state.i + 1
});
}
render() {
let colormap = ["black", "red", "green", "blue"];
let i = this.state.i % colormap.length;
let color = {
color: colormap[i]
};
return (
<div className="dialog">
<h1 style={color}>HelloWorld</h1>
<button onClick={this.handleClick}>チェンジ</button>
</div>
);
}
}
ReactDOM.render(
<Dialog />,
document.getElementById('root')
);
</script>
</body>
</html>
はじめてのReact #16「Componentの連携」子要素にアクセスする
これまでは、最終的にrender()
する際には<Foo />
のようにタグで何らかの文字列や要素を囲わない状態でした。今回はそこから一歩進んで<Foo>Hello!</Foo>
のように何らかの要素を挟んでみたいと思います。
ダイアログ Component
おもしろサンプルが思いつかなかったので、公式ドキュメントほぼそのまま、ダイアログの作成を行います。
サンプル
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Dialog</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>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
class Dialog extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div style={{backgroundColor:'lightpink', width:'500px', border:'5px solid red'}}>
{this.props.children}
</div>
);
}
}
ReactDOM.render(
<Dialog>
<h1>Hello! World</h1>
nice to meet you!
</Dialog>,
document.getElementById('root')
);
</script>
</body>
</html>