ローカル開発環境構築
Reactはスクラッチからコードを書くのではなく、公開されているパッケージ類を組み合わせて開発環境を構築する。
パッケージはnpmコマンドでインストールする。
現在はcreate-react-appパッケージを入れれば必要なものは大方含まれている。
node.js インストール(npmコマンドを使うために)
https://nodejs.org/ja/download/create-react-appコマンドを利用可能にするためグローバルインストール
c:\>npm install -g create-react-app
- プロジェクトの雛形を作成
c:\>create-react-app my-app
- ↑で作成されたpackage.jsonに記載されているパッケージをまとめてインストール
(node_modulesディレクトリにパッケージがインストールされる)
c:\>cd my-app
c:\my-app>npm install
- ビルド実行+ローカルサーバー起動
c:\my-app>npm start
> my-app@0.1.0 start c:\my-app
> react-scripts start
Starting the development server...
Compiled successfully!
You can now view my-app in the browser.
Local: http://localhost:3000/
On Your Network: http://192.168.56.1:3000/
Note that the development build is not optimized.
To create a production build, use npm run build.
↑に出てきた http://localhost:3000/ にアクセスすると雛形ページが見れる。
index.htmlやApp.jsを変更すると反映されるのが確認できる。
ビルド
コンパイルしてアプリケーションに配備可能な状態にする。
c:\my-app>npm run buril
my-appディレクトリにbuildディレクトリが作成される。
この中にjsやらhtmlやらが生成されている。
アプリケーションに上記をアプリケーションに配置、もしくはしかるべき場所にbuildされるようにしておく。
ワークショップ
準備
Ctrl+Cで一旦ローカルサーバーを止め、
- 雛形ファイルを削除
c:\my-app>del src\
c:\my-app>del public\
- 空ファイルを作成
c:\my-app>del src\index.js #空
c:\my-app>del public\index.html
<html>
<body>
Hello World!
<body>
</html>
npm start するとHello World!が確認できる。
この状態で index.js だったり index.html を編集していくことで開発できる。
Hello World!を表示する
<html>
<body>
<div id="content">
<!-- ここに生成されたDOMが書き出されます -->
</div>
<body>
</html>
import App from './App';
import React from 'react';
import ReactDOM from 'react-dom';
ReactDOM.render(
React.createElement(
'p',
{ className: 'Hello' },
'Hello World!'
),
document.getElementById('content')
);
Hello World!でました!!!!!
入れ子のタグを作るときはこう。
ReactDOM.render(
React.createElement(
'p',
{ className: 'Hello' },
React.createElement(
'span',
{ className: 'Hello2' },
'Hello World!'
),
),
document.getElementById('content')
);
すごく見にくいので
JSX(jsの中にマークアップを書ける拡張構文)にしよう。
ReactDOM.render(
// 指定したタグを書き出す
// ※ 入れ子はできるけど、ルートの階層に複数タグを書くことはできない
<p className='Hello'>
<span className='Hello2'>Hello World!</span>
</p>,
document.getElementById('content')
);
みやすい!!!!!!ヽ(゜∀。)ノ
Component化
さきほどの Hello World! をコンポーネント化します。
import React from 'react';
import ReactDOM from 'react-dom';
import Hello from './Hello';
ReactDOM.render(
<Hello />,
document.getElementById('content')
);
import React, { Component } from 'react';
class Hello extends Component {
render() { // 定義したコンポーネントをレンダリングするためのメソッド
return(
<p className='Hello'>
<span className='Hello2'>Hello World!</span>
</p>
);
}
}
export default Hello; // 定義したHelloをimport可能にする
値のやり取り
props:親から渡される情報(≒引数)
state:自Componentの状態
Hello World! の文字列を親から渡してみる
import React from 'react';
import ReactDOM from 'react-dom';
import Hello from './Hello';
ReactDOM.render(
<Hello helloTitle='Hello World!' />,
document.getElementById('content')
);
import React, { Component } from 'react';
class Hello extends Component {
render() {
return(
<p className='Hello'>
<span className='Hello2'>{this.props.helloTitle}</span>
</p>
);
}
}
export default Hello;
Hello World! の文字列の状態を変更してみる
import React, { Component } from 'react';
class Hello extends Component {
constructor(props) {
super();
// 親から受け取ったpropsをstateの初期値とする
this.state = { helloTitle: props.helloTitle };
}
changeText() {
// 自コンポーネントのイベントにより状態を変更
this.setState({ helloTitle: 'Hello World!!!!!!' } );
}
render() {
return(
<p className='Hello' onClick={ () => this.changeText() }>
<span className='Hello2'>{this.state.helloTitle}</span>
</p>
);
}
}
export default Hello;
ここでは簡単に無名関数で onClick={ () => this.changeText() } と直接実行していますが、onClick={this.changeText} としてイベントを紐づけたほうがよいでしょう。
しかしその場合、イベント実行時にthisがバインドされない(changeText実行時にthis.setStateがundefinedになる)ので、super()後に下記を記述しておく必要があります。
this.changeText = this.changeText.bind(this);
繰り返し処理
import React from 'react';
import ReactDOM from 'react-dom';
import Hello from './Hello';
const hellos = ['Hello', 'こんにちは', 'Здравствуйте'];
ReactDOM.render(
<Hello hellos={hellos} />,
document.getElementById('content')
);
import React, { Component } from 'react';
class Hello extends Component {
render() {
// 配列データをmapメソッドで return JSX する
const hellos = this.props.hellos.map((text) => {
return <p>{text}</p>;
});
return(
<p className='Hello'>
{hellos}
</p>
);
}
}
export default Hello;
これでもいい(定数に格納しないでjsx内に直接jsを書くことも出来る)
<p className='Hello'>
{this.props.hellos.map((text) => {
return <p>{text}</p>;
})}
</p>
コンポーネントのライフサイクル
import React, { Component } from 'react';
class Hello extends Component {
constructor(props) {
super();
alert('①constructor');
this.changeText = this.changeText.bind(this);
// 親から受け取ったpropsをstateの初期値とする
this.state = { helloTitle: props.helloTitle };
}
componentWillMount() {
alert('②componentWillMount');
}
render() {
alert('render');
return(
<p className='Hello' onClick={this.changeText}>
<span className='Hello2'>{this.state.helloTitle}</span>
</p>
);
}
componentDidMount() {
alert('③componentDidMount');
}
// --------------------------------
// 廃止予定
componentWillReceiveProps(nextProps) {
alert('④componentWillReceiveProps');
}
shouldComponentUpdate(nextProps, nextState) {
alert('⑤shouldComponentUpdate');
// propsとstateの前後の状態を比較して再描画をコントロール
if (this.helloTitle === nextState.helloTitle) {
// 差分がないので無駄な再描画をしない
return false;
}
return true;
}
// 廃止予定
componentWillUpdate() {
alert('⑥componentWillUpdate');
}
componentDidUpdate() {
alert('⑦componentDidUpdate');
// 変化後のDOMを処理したい場合など
}
componentWillUnMount() {
alert('⑧componentWillUnMount');
// コンポーネントがDOMから削除される直前に実行される
// 関連するイベントの後片付け的な処理やタイマーのキャンセルなど
}
changeText() {
// 自コンポーネントのイベントにより状態を変更
this.setState({ helloTitle: 'Hello World!!!!!!' } );
}
}
export default Hello;