Reactとは
・UIを構築するためのJSライブラリ
・HTMLを直接は使わずJavaScriptで動的にUI生成する仕組み
・JavaScriptのエコシステム(テストツールなど)が使える
・コンポーネント指向で、独立した部品を組み合わせて作る
・Virtual DOMを用いた画面の差分描画を行い高速な画面表示を実現する
①コンポーネントとは
・UIの構成要素
・Reactでは、コンポーネントを組み合わせてUIを作る
・コンポーネントには表示系のだけでなく処理も記述する
②ステート
・コンポーネントの内部の変数のようなもの
・コンポーネントが生成される際に初期化され、その後はコンポーネントの状態の変化を保持するために使われる。
・コンポーネントの外部からはアクセスできない。
・ステートに頼らず、使わないで済むなら使わない方が良い
③プロパティ
・コンポーネントに外部から与えられるオプションのようなもの。
・HTMLで言う属性のようなもの。
・コンポーネントの内部では、プロパティはステートと同じように変数としてアクセスできる。
・コンポーネントはプロパティの値を変更してはいけない。
・プロパティは外の世界から一方的に伝えられるもので、それを使って外に何かを発信することはできない。
④JSX
・JavaScriptの中でXMLの文法によってReactコンポーネントを配置できるようにした言語。
・XMLライクのシンタックスを追加する言語拡張。
・JSXを使うとJavaScriptの中にHTMLのタグを埋め込むように記述することができる
⑤Virtual DOM
・
・Reactが内部で使っている仕組み
・JavaScriptで生成したDOMを模倣したデータ構造で差分計算をして、実際のDOMに反映させるため、処理が高速になる
const element = <h1 className="hello">これはJSXです</h1>;
const App = () => (
<div>Hello React!</div>
);
const render = () => ReactDOM.render(<App />, document.getElementById('app'));
render();
//・「App」App内で定義されている<div>はHTMLの記法と似ています。これはJSXと言ってXMLであり正確にはJavaScriptに変換されるもの。
//・「render」Reactコンポーネントをブラウザに描画するためのもの
Reactのコンポーネントは再利用可能なパーツ
//コンポーネント定義
const Hello = () => (
<div>Hello</div>
);
//コンポーネントを使う
const App = () => (
<div>
<Hello />
</div>
);
・コンポーネントはHTMLのタグと区別するためコンポーネントは大文字で始まる名前にする。
・XMLはHTMLと違い必ず閉じタグが必要。 はの省略記法
・コンポーネントの定義は 使う位置より上に書くようにする
コンポーネントにスタイルをつける
・HTMLでCSSを使ってスタイルをつけるように、コンポーネントでも同じことができる。
・ReactではInline stylesという方法でスタイルをつける。
const Hello = () => (
<div style={{ color: 'red'}}>Hello</div>
);
・外側はReact、内側はJS
const myStyle = {
color: 'red',
marginLeft: 100,
};
・CSSと違いキャメルケースで
props
・コンポーネントを作る目的は再利用
・再利用が有効に働くようにするにはパラメータを受け取るようにできることが重要
・Reactではコンポーネントが受け取るパラメータオブジェクトをpropsと言う
・propsは通常のJavaScriptオブジェクト
//propsを受け取る
const Hello = ({ name }) => (
//ここの{name}はJSで、{name + '!'}ともかける
//JSX内の{}には任意のJavaScript表現を書くことができる
<div>Hello {name}</div>
);
//propsを渡す
const App = () => (
<div>
//name="World"の部分はname={"Mina" + 3}などとしてJavaScript表現を書くことも可能
<Hello name="World" />
</div>
);
コンポーネントを再利用する
const Hello = ({ name, color }) => (
<div>
//style={}の中の{ color }は{ color: color }の意味
<p style={{ color }}>Hello {name}!</p>
</div>
);
const App = () => (
<div>
<Hello name="World" color="blue" />
<Hello name="Ebisu" color="red" />
</div>
);
配列から展開する
・データなどの配列からコンポーネントを展開することができるとより再利用性の価値が生まれる。
//再利用するコンポーネント
const Hello = ({ name, color }) => (
<div>
<p style={{ color }}>Hello {name}!</p>
</div>
);
//データの展開を利用しない場合
const App = () => (
<div>
<Hello name={items[0].name} color={items[0].color} />
<Hello name={items[1].name} color={items[1].color} />
<Hello name={items[2].name} color={items[2].color} />
<Hello name={items[3].name} color={items[3].color} />
</div>
);
//データの展開を利用する場合
const App = () => (
<div>
{items.map((item) => (
<Hello name={item.name} color={item.color} />
))}
</div>
);
フォームを利用する
//ボタンを表示する
const MyButton = () => (
<div>
<button onClick={() => alert('clicked')}>Click Me</button>
</div>
);
//テキストボックスを制御する
let textData = '';
const setTextData = (event) => {
textData = event.target.value;
//10文字より多く入力できないよう
if (textData.length > 10) {
textData = textData.slice(0, 10);
}
//render()をtextデータが更新されるたびに呼び出す
render();
};
//テキストボックスを定義する
const MyBox = () => (
<div>
<input type="text" value={textData} onChange={setTextData} />
</div>
);
const App = () => (
<div>
<MyBox />
</div>
);
const render = () => ReactDOM.render(<App />, document.getElementById('app'));
・Reactの魅力の一つとして、フォームの値の制御が柔軟にできるということ。
いわゆるフォームのバリデーションが、任意のコードで書くことができる
フォームの使用
const items = [
{ name: 'aaa', color: 'black' },
{ name: 'bbb', color: 'green' },
{ name: 'ccc', color: 'pink' },
{ name: 'ddd', color: 'yellow' },
];
//データを入力した際の処理
let nameData = '';
const setNameData = (event) => {
nameData = event.target.value;
render();
};
//データ追加ボタンをタップした際の処理
const addData = () => {
items.push({ name: nameData, color: 'black' });
nameData = '';
render();
};
//登録フォームの定義
const MyForm = () => (
<div>
<input type="text" value={nameData} onChange={setNameData} />
<button onClick={addData}>Add Data</button>
</div>
);
//表示、削除フォームの定義
const Hello2 = ({ name, color, onDelete }) => (
<div>
<p>
<span style={{ color }}>Hello {name}!</span>
<button onClick={() => onDelete()}>Delete</button>
</p>
</div>
);
//削除処理
const deleteItem = (index) => {
items.splice(index, 1);
render();
};
const App = () => (
<div>
<MyForm />
{items.map((item, index) => (
<Hello2 name={item.name} color={item.color} onDelete={() => deleteItem(index)} />
))}
</div>
);
const render = () => ReactDOM.render(<App />, document.getElementById('app'));
render();
ES2015(ES6)
・ReactでコーデイングするにはES2015が便利。
・ES2015はトランスパイルが必要だけれど、JSXを利用するとトランスパイルするため敷居が下がる。
ES2015について
「const」と「let」
・ES2015ではvarは基本的に使わず、代わりにconstとletを使うことが推奨され
・constは再代入しない変数の宣言に用います。
・letは再代入が必要な変数の宣言に用います。
・再代入とimmutabilityは別物ですので注意が必要です。
const x = 1;
let y = 2;
y = 3;
object shorthand
・ES2015ではオブジェクトのプロパティ名と値の変数名が同じ場合、省略記法を使うことができます。
const foo = 'abc';
const bar = { foo }; // same as { foo: foo }
destructuring object
・destructuring assignmentという簡便な記法
・変数への代入だけでなく、関数のパラメータ宣言でも用います。
const obj = { first: 'Ebisu', last: 'JS' };
const { first, last } = obj;
// first === 'Ebisu', last === 'JS'
function printName({ first, last }) { console.log(first, last); }
printName(obj);
// same as
// function printName(name) { console.log(name.first, name.last); }
アロー関数
・() => ...という記法
const f1 = function(x) { console.log(x); };
const f2 = (x) => { console.log(x); };
// f1 and f2 is almost the same
const f3 = (x) => { return (x + 1); };
const f4 = (x) => (x + 1);
// f3 and f4 is the same
const f5 = x => x + 1;
その他
1. コンポーネントの書き方
(1)ドキュメントに記載されている基本的な書き方
var Hello = React.createClass({
render: function() {
return (
<div>Hello {this.props.name}</div>
);
}
})
(2)ES2015からの書き方
class Hello extends React.Component {
render() {
return (
<div>Hello {this.props.name}</div>
);
}
}
(3)React v0.14から可能になったfunction components
function Hello(props) {
return (
<div>Hello {props.name}</div>
);
}
(4)ES2015の場合はアロー関数でも書ける
const Hello = (props) => (
<div>Hello {props.name}</div>
);
const Hello = (props) => {
// ここに何かしらの処理が入る場合
return (
<div>Hello {props.name}</div>
);
};
(5)ES2015ではpropsを引数宣言で展開することができる
const Hello = ({ name }) => (
<div>Hello {name}</div>
);
function Hello({ name }) {
return (
<div>Hello {name}</div>
);
}
2. コンポーネントのstate
・コンポーネントにはprops以外にもstateと言う状態を持つ手段がある。
class Hello extends React.Component {
constructor() {
this.state = { count: 1 };
this.incrementCount = this.incrementCount.bind(this);
}
incrementCount() {
this.setState({ count: this.count + 1 });
}
render() {
return (
<div>
Hello {this.props.name}
<button onClick={this.incrementCount}>
count={this.state.count}
</button>
</div>
);
}
}
react-compose-state
・個人プロジェクトなどの手軽なコーディングではsingle storeはオーバスペックである場合もあります。そのような場合でコンポーネントレベルのstateを使いつつ、上記のようなclassを使わない方法としてreact-compose-stateがあります。
const Hello = composeWithState({ count: 1 })(({ name, count, setCount }) => (
<div>
Hello {name}
<button onClick={() => setCount(count + 1)}>
count={count}
</button>
</div>
);
3. コンポーネントのライフサイクルメソッド
・コンポーネントにはライフサイクルメソッドというものがある。
・コンポーネントが初めて使われた時にDOMレンダリング後に呼ばれるもの。
class Hello extends React.Component {
componentDidMount() {
console.log('Hello component is initialized.');
}
render() {
return (
<div>
Hello {this.props.name}
</div>
);
}
}
4. PropTypes
・PropTypes指定すると、propsが不足していたり、型が異なる時などに、分かりやすいエラーメッセージが出てくるため、デバッグが楽になる。
const Hello = ({ name }) => (
<div>Hello {name}</div>
);
Hello.propTypes = {
name: React.PropTypes.string.isRequired,
};
const Hello = ({ name } = { name: 'World' }) => (
<div>Hello {name}</div>
);
5. コンポーネントを2種類に分類した例
・コンポーネントの役割を2種類に分ける
・「presentational component」表示に特化するコンポーネント
・「container component」データの処理を扱うコンポーネント
・分離すると、presentation componentがデータレイヤから切り離されるため、再利用性が上がるというメリットがあります。
const Hello = ({ name, onClickButton }) => (
<div>
Hello {name}
<button onClick={onClickButton}>Click me</button>
</div>
);
const HelloContainer = ({ store }) => (
<Hello
name={store.getState().name}
onClickButton={store.dispatch({ type: 'CHANGE_NAME_RANDOMLY' })}
/>
);
Reduxとは
・Reduxはimmutabilityを基本としたUIの状態を管理するためのフレームワーク。
Application Stateとは
・アプリケーションの状態で、単一のデータ構造で表現するもの。
・状態を保持する変数を一箇所に集中して管理する。
let state = {
inputValue: 0,
resultValue: 0,
showingResult: false,
};
Actionとは
・actionはstateを変化させる操作のっこと
・actionはtypeプロパティを持つオブジェクト
・actionには任意のプロパティを追加することができる。
const action = { type: 'PLUS' };
const action1 = { type: 'INPUT_NUMBER', number: 1 };
const action2 = { type: 'INPUT_NUMBER', number: 2 };
ActionCreaterとは
・Actionを作る関数
・必須ではない
const doPlus = () => ({
type: 'PLUS',
});
const inputNumber = (number) => ({
type: 'INPUT_NUMBER',
number,
});
console.log(doPlus());
console.log(inputNumber(3));
console.log(inputNumber(4));
console.log(inputNumber(5));
Reducer
・stateとactionを入力とし、新しいstateを返す関数
・actionはstateを変化させる操作
・stateを変化させることができるのはreducer
・状態と状態操作を受け取り新しい状態を作る関数
例)新しい状態 = Reducer(今の状態, 状態操作);
state = reducer(state, action);
Store
・application stateを管理する場所
React環境構築
・VirtualBox centos7
(1)Node.js / npm導入
・NVMで導入する
#nvmをクローン
git clone git://github.com/creationix/nvm.git ~/.nvm
#.bashrcに、nvmを登録
echo . ~/.nvm/nvm.sh >> ~/.bashrc
#.bashrc再読み込み
. ~/.bashrc
#nodeのインストール
nvm install stable
(2)プロジェクトの初期化
mkdir プロジェクト名
cd プロジェクト名
npm init
=>「package.json」が作成される
(3)webpackのインストール
npm install --save webpack
(4)React / Babelのインストール
npm install --save react react-don
モジュール名 | 概要 |
---|---|
react | |
react-dom |
npm install --save babel-core babel-loader babel-preset-es2015 babel-preset-react
モジュール名 | 概要 |
---|---|
babel-core | |
babel-loader | |
babel-preset-es2015 | |
babel-preset-react |
()トップページのhtmlを自動生成するPlugin
npm install --save-dev html-webpack-plugin
(5)webpackの設定ファイルを作成
・webpackを実行する際の設定ファイル
const path = require('path');
module.exports = {
entry: {
bundle: './src/app.js'
},
output: {
path: path.join(__dirname, 'public'),
filename: '[name].js'
},
module: {
loaders: [
{
loader: 'babel',
exclude: /node_modules/,
test: /\.js[x]?$/,
query: {
cacheDirectory: true,
presets: ['react', 'es2015']
}
}
]
}
};
webpackコマンド | 概要 |
---|---|
context | entryオプションを解決するためのベースとなる絶対パス |
devtool | ブラウザの開発者ツールなどでビルド前のコードを参照することができる |
entry | ビルドの起点となるファイルのパスを指定する |
output.path | 出力先のパス |
output.filename | 出力ファイル名 |
module.loaders | 対象のファイルを変換するためのloaderを指定。 |
module.loaders.test | Loaderを適用するファイルを指定する |
module.loaders.loader | 通すLoaderを指定する。 |
plugins | |
resolve |
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
query:{
presets: ['react', 'es2015']
}
}
]
node_modules ディレクトリ配下を除き、拡張子が .js のファイルすべてに対し、babel-loader という loader を適用します。
また、適用する際、loader に react と es2015 という preset を指定します。