イベントシステム
React は仮想 DOM に基づいて SyntheticEvent レイヤーを実装し、SyntheticEvent オブジェクトのインスタンスを受け取るハンドラを定義します。これは、W3C 標準に完全に準拠しており、IE との互換性の問題はありません。 これは、ブラウザのネイティブイベントと同じインターフェイスを持ち、同じイベントバブリングメカニズムをサポートしています。ネイティブ・イベント・オブジェクトにアクセスする必要がある場合は、nativeEvent プロパティを使用します。
合成イベントの結合方法
Reactイベントは、ネイティブのHTMLイベントリスナープロパティと非常によく似た方法でバインドされます。
<button onClick={this.handleClick}>Test</button>
合成イベントを実装するメカニズム
Reactの底辺には、合成イベントに対して行われる2つの主要なことがあります:イベントの委譲と自動バインディングです。
1.インシデントの割り当て
イベントハンドラを実際のノードに直接バインドする代わりに、Reactは、すべてのコンポーネントの内部イベントリスナーとハンドラを保持するマッピングを維持する統一イベントリスナーを使用して、構造の一番外側のレベルにすべてのイベントをバインドします。コンポーネントがマウントまたはアンマウントされると、統一イベントリスナーからオブジェクトを挿入または削除するだけです。イベントが発生すると、まず統一イベントリスナーによって処理され、次に実際のイベントハンドラがマッピングで見つかり、呼び出されます。これはイベントハンドリングとリサイクルのメカニズムを単純化し、効率を大幅に向上させます。
2.自動バインディング
Reactコンポーネントでは、各メソッドのコンテキストはコンポーネントのインスタンスを指します。そしてReactはこの参照をキャッシュします。ES6クラスや純粋な関数を使用する場合、この自動バインディングはもはや存在せず、手動で "this "バインディングを実装する必要があります。バインドメソッドをいくつか見てみましょう。
class App extends Component {
 constuctor() {
 super(props)
 this.handleClick = this.handleClick.bind(this)
 }
}
アロー関数は、関数のスコープの "this "に自動的にバインドすることができます。
class App extends Component {
 handleClick= () => {}
}
Reactでのネイティブイベントの使用
class bar extends Component {
    .b() {
        this.foo.button.addEventListener('click', this.obj);
    }
    .a() {
        this.foo.button.removeEventListener('click', this.obj);
    }
}Reactの合成イベントとJavaScriptのネイティブイベントの比較
1.事象の発信と拡散防止
ブラウザネイティブのDOMイベントの伝播は、イベントキャプチャ段階、ターゲットオブジェクト自身のイベントハンドラ呼び出し、イベントバブリングの3段階に分けることができます。e.addEventListenerの3番目のパラメータをtrueに設定することで、要素eのキャプチャイベントハンドラを登録することができます。イベントキャプチャはIE9以下では利用できません。イベントキャプチャはアプリケーション開発ではあまり意味がなく、Reactは複合イベントでのイベントキャプチャを実装しておらず、イベントバブリングの仕組みのみをサポートしています。
ネイティブイベントの伝播を停止するには、e.stopPropagationを使用する必要がありますが、このメソッドをサポートしていないブラウザでは、e.cancelBubble = trueを使用して停止することしかできません。代わりに、Reactの複合イベントでは、stopPropagation()を使用するだけです。Reactイベントのバブリングを停止する方法は、Reactコンポジットイベントシステムでのみ使用でき、ネイティブイベントのバブリングを停止する方法はありません。代わりに、ネイティブイベントはバブリングを防止し、React合成イベントの伝播を停止することができます。
2.イベントの種類
React複合イベントのイベントタイプは、JavaScriptのネイティブイベントタイプのサブセットです。これは単に DOM Level 3 イベントインターフェースを実装し、ブラウザの互換性の問題を統一したものです。Reactが実装していないイベントや、特定の制限のために実装できないイベントもあります(ウィンドウのリサイズイベントなど)。
3.イベントバインディングメソッド
ブラウザは、DOM標準の影響を受けて、さまざまな方法でネイティブイベントをバインドします。
<button onClick={this.handleClick}>Test</button>
4.イベントオブジェクト
Reactの合成イベントシステムでは、合成イベントオブジェクトを取得するための互換性の問題はありません。
けいしき
Reactでは、もちろんフォームデータも含めて、すべてがステートです。次はReactがフォームをどのように扱うかです。
申請書の構成要素
htmlフォームのコンポーネントはすべてReactのJSXで実装されていますが、JSXの構文に起因するもの、Reactのステートの扱いに起因するものなど、使い方にいくつか違いがあります。
1.テキストボックス
import React, { Component } from 'react';
class App extends Component {
 constructor(props) {
 super(props);
 this.state = {
 inputValue: '',
 textareaValue: ''
 }
 }
 handleInputChange = (e) => {
 this.setState({
 inputValue: e.target.value
 });
 }
 handleTextareaChange = (e) => {
 this.setState({
 textareaValue: e.target.value
 })
 }
 render() {
 const { inputValue, textareaValue } = this.state;
 return (
 <div>
 <p>
 一行入力ボックス:
 <input type="text" value={inputValue} onChange={this.handleInputChange}/>
 </p>
 <p>
 複数行の入力ボックス:
 <textarea type="text" value={textareaValue} onChange={this.handleTextareaChange}/>
 </p>
 </div>
 )
 }
}HTMLではtextareaの値はchildrenによって表現されますが、reactではvalue propがフォームの値を表現するために使われます。
2.ラジオボタンとチェックボックス
HTMLでは、ラジオボタンはradio型のinputタグで表現され、チェックボックスはcheckbox型のinputタグで表現されます。両方のフォームのVALUE値は一般的に変化しませんが、チェックされているかどうかを示すためにboolean型のchecked propによって示されます。これらはJSXでも同じですが、使い方に若干の違いがあります。
ラジオボタンの例
import React, { Component } from 'react';
class App extends Component {
 construtor(props) {
 super(props);
 this.state = {
 radioValue: '',
 }
 }
 handleChange = (e) => {
 this.setState(
 radioValue: e.target.value
 )
 }
 render() {
 const { radioValue } = this.state;
 return (
 <div>
 <p>gender:</p>
 <label>
 male:
 <input 
 type="radio"
 value="male"
 checked={radioValue === 'male'}
 onChange={this.handleChange}
 />
 </label>
 <label>
 female:
 <input 
 type="radio"
 value="female"
 checked={radioValue === 'female'}
 onChange={this.handleChange}
 />
 </label>
 </div>
 )
 }
}
チェックボタンの例
import React, { Component } from 'react';
class App extends Component {
 constructor(props) {
 super(props)
 
 this.state = {
 coffee: []
 }
 }
 handleChange = (e) => {
 const { checked, value } = e.target;
 let { coffee } = this.state;
 if (checked && coffee.indexOf(value) === -"1") {
 coffee.push(value)
 } else {
 coffee = coffee.filter(i => i !== value)
 }
 this.setState({
 coffee,
 })
 }
 render() {
 const { coffee } = this.state;
 return (
 <div>
 <p>お好きなコーヒーをお選びください</p>
 <label>
 <input 
 type="checkbox"
 value="Cappuccino"
 checked={coffee.indexOf('Cappuccino') !== - }
 onChange={this.handleChange}
 />
 Cappuccino
 </label>
 <br />
 <label>
 <input 
 type="checkbox"
 value="CafeMocha"
 checked={coffee.indexOf('CafeMocha') !== - }
 onChange={this.handleChange}
 />
 CafeMocha
 </label>
 </div>
 )
 }
}3.コンポーネントの選択
HTML の select 要素には、単一選択と複数選択の両方があります。JSX構文では、selectタグにmultiple={true}を設定することで、複数選択のドロップダウンリストを実装することもできます。
class App extends Component {
 constructor(props) {
 super(props)
 this.state = {
 area: ''
 }
 }
 handleChange = (e) => {
 this.setState({
 area: e.target.value
 })
 }
 render() {
 const { area } = this.state;
 return (
 <select value={area} onChange={this.handleChange}>
 <option value='Tokyo'> </option>
 <option value='shangehai'> </option>
 </select>
 )
 }
}select 要素に multiple={true} を設定す る 例。
class App extends Component {
 constructor(props) {
 super(props)
 this.state = {
 area: ['Tokyo', 'Tokyo']
 }
 }
 handleChange = (e) => {
 const { options } = e.target;
 const area = Object.keys(options)
 .filter(i => options[i].selected === true)
 .map(i => options[i].value);
 this.setState({
 area,
 })
 }
 render () {
 const { area } = this.state;
 return (
 <select multiple={true} value={area} onChange={this.handleChange}>
 <option value=" "> </option>
 <option value=" "> </option>
 </select>
 )
 }
}HTMlのoptionコンポーネントは、デフォルトで選択されるリストアイテムを示すためにselectedプロパティを必要とします。Reactは、選択されたオプションを示すためにselectコンポーネントにvalue propを追加することでこれを処理し、インターフェイスをある程度統一します。
実際、この形式で書くこともできますが、開発体験はもっと悪くなり、Reactは警告を投げます。
<select multiple={true} onChange={this.handleChange}>
 <option value="Tokyo" selected={area.indexOf('Tokyo') !== - }> </option>
 <option value="Tokyo" selected={area.indexOf('Tokyo') !== - }> </option>
</select>制御部品
フォームの状態が変更されるたびに、その状態がコンポーネントの状態に書き込まれます。コントロールされたコンポーネントでは、コンポーネントはその値またはチェックされたpropに対応する状態をレンダリングします。Reactはこの方法でコンポーネントのローカル状態を排除し、アプリケーションの状態全体をよりコントロールしやすくします。
制御不能なコンポーネント
フォームコンポーネントがvalue prop(またはchecked prop)を持たない場合、それはuncontrolled componentと呼ばれます。したがって、defaultValueとdefaultCheckedプロップを使用して、コンポーネントのデフォルト状態を示すことができます。
class App extends Compoent {
 constructor(props) {
 super(props)
 }
 handleSubmit = (e) => {
 e.preventDefault();
 const { value } = this.refs.name;
 console.log(value)
 }
 render() {
 return (
 <form onSubmit={this.handleSubmit}>
 <input ref="name" type="text" defaultValue="Hangzhou" />
 <button type="submit">submit</button>
 </form>
 )
 }
}
Reactにおいて、制御されないコンポーネントとは、コンポーネント自身のステートやプロップによって値が制御されないアンチパターンです。典型的には、レンダリング後に基礎となるDOM要素にアクセスするためにref propを追加する必要があります。
制御部品と非制御部品の比較対照
制御されるコンポーネントと制御されないコンポーネントの大きな違いは、制御されないコンポーネントの状態がアプリケーションの状態によって制御されず、アプリケーション内のローカルなコンポーネントの状態が多いのに対し、制御されるコンポーネントの値はコンポーネントの状態から来るということです。
1.パフォーマンスの問題
制御されたコンポーネントのonChangeの後にsetStateを呼び出すと、再レンダリングが行われるため、パフォーマンスが低下します。
2.イベントバインディングが必要かどうか
制御されたコンポーネントは、各コンポーネントに変更イベントをバインドし、フォームの値とコンポーネントの状態を同期させるイベントハンドラを定義する必要があります。
とはいえ、アプリケーション全体の状態をより制御しやすくするため、Reactでは制御されたコンポーネントの使用が推奨されています。
フォーム・コンポーネントのいくつかの重要な特性
1.州の属性
Reactのフォームコンポーネントは、コンポーネントの状態を表示するためのいくつかの重要なプロパティを提供します。value: text 型の入力コンポーネント、textarea コンポーネント、select コンポーネントは value prop の助けを借りてアプリケーションの状態を表示します。checked: radio または checkbox タイプのコンポーネントは、boolean タイプの値を持つ checked プロップの助けを借りてアプリケーションの状態を表示します。selected: このプロパティはselectコンポーネントの下のオプションで使用できますが、Reactはこの方法の使用を推奨しておらず、valueの使用を推奨しています。
2.イベントプロパティ
onChange イベントプロパティは、state プロパティが変更されたときにトリガされます。Reactは、DOM Level3で定義されているすべてのフォームイベントをサポートしています。
スタイリング
基本スタイル設定
classnamesライブラリの使用
classnamesライブラリを使用すると、htmlのクラス名を設定できます。
CSS Modules
CSSのモジュール化には多くの解決策がありますが、大きく2つに分類できます。
- インライン スタイル: このアプローチでは、CSS を完全に放棄し、JavaScript または JSON を使用してスタイルを記述するため、CSS に JavaScript が提供する強力なモジュール性を与えることができます。しかし、欠点も同様に明らかで、カスケード、メディア クエリなどの CSS 独自の機能をほとんど利用できず、:hover や :active などの擬似クラスを扱うのがより複雑になります。さらに、この解決策は、React、Radium、jsxstyle、react-styleに関連するフレームワークの実装に依存する必要があります。
- CSS Modules: CSS は引き続き使用しますが、スタイルの依存関係を管理するために JavaScript を使用します。 CSS Modules は、既存の CSS エコシステムと JavaScript のモジュール性を最大化し、非常にクリーンな API を提供します。このリリースでは、JavaScript と CSS ファイルを別々にコンパイルします。CSS Modulesはwebpackのcss-loaderに組み込まれました。
1.CSSのモジュール性にはどのような問題がありましたか?
CSSスタイルのインポートとエクスポートです。Sass、Less、PostCSSなどは、CSSのプログラミング能力が弱いという問題を解決しようとしていますが、モジュール性の問題は解決していません:
- グローバルな汚染:CSSはスタイルを設定するのにグローバル・セレクタの仕組みを使います。 メリットはスタイルの書き換えが簡単なことです。欠点は、すべてのスタイルがグローバルに適用されるため、誤ってスタイルを上書きしてしまう可能性があることです。Web Component標準のShadow DOMはこの問題を完全に解決しますが、スタイルを完全に局所化するため、外部からスタイルを書き換えることができず、柔軟性が失われます。
- ネーミングの混乱:世界的な公害問題、複数人での共同開発のため、スタイルの競合を避けるために、セレクタがますます複雑になっている、簡単に別のネーミングスタイルを形成するために、スタイルが多くなり、ネーミングがより混乱されます。
- 依存関係の管理は不完全です。コンポーネントは互いに独立しているべきで、コンポーネントを導入するときは、そのコンポーネントが必要とするCSSスタイルだけを導入すべきです。JavaScriptのモジュール性は非常に成熟しており、JavaScriptがCSSの依存関係を管理することは良い解決策です。そしてwebpackのcss-loaderはその機能を提供します。
- 変数を共有できない:スタイルを処理するために JavaScript と CSS を一緒に使用しなければならない複雑なコンポーネントでは、JavaScript と CSS で一部の変数が冗長になります。
- 不完全なコード圧縮:非常に長いクラス名を圧縮することはできません。
2.CSSモジュール
CSS Modulesは、ICSSを通じてスタイルのインポートとエクスポートの問題を内部的に解決しており、これは2つの新しい擬似クラス:importと:exportにそれぞれ対応しています。
:import("path/to/dep.css") {
 localAlias: keyFromDep;
}
:export {
 exportedKey: exportedValue;
}
しかし、この2つのキーワードで直接プログラミングするのはとても面倒なので、プロジェクトで直接使われることはほとんどなく、必要なのはJavaScriptでCSSを管理する機能です。webpackのcss-loaderと組み合わせることで、CSSでスタイルを定義し、JavaScriptファイルに書き出すことができます。
CSSモジュールの有効化
css?modules&localIdentName=[name]__[local]-[hash:base64:5]
localIdentNameはスタイルを生成するための命名規則を設定します。
ここでは、jsがどのようにCSSを導入しているかを見てみましょう:
/* buttonに関連するすべてのスタイル */
.normal {}import foo from './Button.css';
buttonElm.outerHTML = '<button\x20class=' + foo.obj + '>Submit</button>';結果の HTML は次のようになります。
<button class="button--normal-abc5436">Processing...</button>
こうすることで、クラス名は基本的に一意になります。CSS Modules は CSS 内のすべてのクラス名を扱い、オブジェクトを使って元のクラスと難読化されたクラスの対応を保持します。この単純な処理で、CSS Modules は以下のことを実現します:
- すべてのスタイルはローカライズされ、ネーミングの衝突や世界的な汚染問題を解決します。
- クラス名生成ルールは柔軟で、クラス名を圧縮するために使用することができます。
- コンポーネントのJavaScriptを参照するだけで、コンポーネントのJavaScriptとCSSをすべて引き受けることができます。
- 学習コストはほぼゼロ
スタイル デフォルト ローカル
CSSモジュールを使用することは、スタイルをローカライズするために各クラス名に:localを追加することと同じです。グローバル・モードに切り替えたい場合は、:global を使って
.normal {
 color: green;
}
/* 上記と同等である */
:local(.normal) {
 color: green;
}
/* グローバルスタイルを定義する */
:global(.btn) {
 color: red;
}
/* 複数のグローバルスタイルを定義する */
:global {
 .link {
 color: green;
 }
 .box {
 color: yellow;
 }
}コンポーズを使ったスタイルの組み合わせ
スタイルの再利用のために、CSSモジュールはそれを扱う唯一の方法を提供します。
/* components/Button.css */
.base { /* すべての一般的なスタイル */ }
.normal {
 composes: base;
 /* normalその他のスタイル */
}さらに、コンポーズを使用して、外部ファイルからスタイルを組み合わせることができます。
/* settings.css */
.primary-color {
 color: #f4 ;
}
/* component/Button.css */
.base { /* すべての一般的なスタイル */ }
.primary {
 composes: base;
 composes: $primary-color from './settings.css'
}ほとんどのプロジェクトでは、composesを使用すると、プロセッサを事前にコンパイルする必要がなくなりました。しかし、composesは標準的なCSS構文ではないため、コンパイル時にエラーが報告され、この時点ではスタイルの再利用を行うために独自の構文のプリプロセッサーを使用することしかできません。
クラス名のヒント
CSS モジュールの命名規則は BEM を拡張したもので、スタイル名を次の 3 つのクラスに分類します。
- ブロック:対応するモジュール名。
- 要素:対応するモジュールのノード名 確認ボタン
CSSとJavaScriptの変数共有の実装
export キーワードを使うと、CSS から JavaScript に変数をエクスポートできます。
$primary-color: #f4 ;
:export {
 primaryColor: $primary-color;
}import c from 'config.scss';
console.log(c.foo);CSSモジュールのヒントとコツ
以下の原則に従うことが推奨されます。
- セレクタを使わずにクラス名だけでスタイルを定義
- 複数のクラスをカスケードする代わりに、1つのクラスですべてのスタイルを定義します。
- すべてのスタイルはコンポーズの組み合わせによって再利用されます。




