ES6 なしで React を使う
この記事は古くなっており、今後更新されません。新しい React 日本語ドキュメントである ja.react.dev をご利用ください。
通常、React コンポーネントはプレーンな JavaScript クラスとして定義されます。
class Greeting extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
もしあなたがまだ ES6 を使っていないのであれば、代わりに create-react-class
モジュールを使うことができます。
var createReactClass = require('create-react-class');
var Greeting = createReactClass({
render: function() {
return <h1>Hello, {this.props.name}</h1>;
}
});
ES6 のクラス API は createReactClass()
とよく似ていますが、いくつかの例外があります。
デフォルト props の宣言
関数や ES6 クラスでは、defaultProps
はコンポーネント自体のプロパティとして定義されます。
class Greeting extends React.Component {
// ...
}
Greeting.defaultProps = {
name: 'Mary'
};
createReactClass()
の場合、渡されるオブジェクト内の関数として getDefaultProps()
を定義する必要があります。
var Greeting = createReactClass({
getDefaultProps: function() {
return {
name: 'Mary'
};
},
// ...
});
state の初期値の設定
ES6 クラスでは、コンストラクタで this.state
へ代入することで state の初期値を定義できます。
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {count: props.initialCount};
}
// ...
}
createReactClass()
の場合、state の初期値を返す getInitialState
メソッドを別途用意しなければなりません。
var Counter = createReactClass({
getInitialState: function() {
return {count: this.props.initialCount};
},
// ...
});
自動バインド
ES6 クラスとして宣言された React コンポーネントでは、メソッドは通常の ES6 クラスと同様のセマンティクスに従います。つまり、this
がそのインスタンスへ自動的にバインドされることはありません。コンストラクタで明示的に .bind(this)
を利用する必要があります。
class SayHello extends React.Component {
constructor(props) {
super(props);
this.state = {message: 'Hello!'};
// This line is important!
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
alert(this.state.message);
}
render() {
// Because `this.handleClick` is bound, we can use it as an event handler.
return (
<button onClick={this.handleClick}>
Say hello
</button>
);
}
}
createReactClass()
の場合は全てのメソッドがバインドされるため、明示的なバインドは必要ありません。
var SayHello = createReactClass({
getInitialState: function() {
return {message: 'Hello!'};
},
handleClick: function() {
alert(this.state.message);
},
render: function() {
return (
<button onClick={this.handleClick}>
Say hello
</button>
);
}
});
これはつまり、ES6 クラスで書くとイベントハンドラのための定型文が少し多くなってしまうということなのですが、一方では大きなアプリケーションの場合にわずかながらパフォーマンスが向上するという側面もあります。
この定型文的コードがあまりに醜く感じられる場合、ES2022 のクラスプロパティ構文を利用できます:
class SayHello extends React.Component {
constructor(props) {
super(props);
this.state = {message: 'Hello!'};
}
// Using an arrow here binds the method:
handleClick = () => {
alert(this.state.message);
};
render() {
return (
<button onClick={this.handleClick}>
Say hello
</button>
);
}
}
他の選択肢もあります。
- コンストラクタでメソッドをバインドする。
- 例えば
onClick={(e) => this.handleClick(e)}
のような形でアロー関数を利用する。 - 引き続き
createReactClass
を利用する。
ミックスイン
補足:
ES6 はミックスインのサポートを含んでいません。従って、React を ES6 クラスで使う場合にミックスインのサポートはありません。
加えて、ミックスインを用いたコードによる多くの問題が見つかっており、新規コードで利用することは推奨されません。
この節は参考のためだけに存在します。
時には同じ機能が全く異なるコンポーネント間で共有されることがあります。これは横断的関心事 (cross-cutting concerns) と呼ばれることがあります。createReactClass
であれば、横断的関心事のためにレガシーな mixins
機能を使うことができます。
よくある利用例のひとつは、一定時間ごとに自分自身を更新するコンポーネントです。setInterval()
を使うのは簡単ですが、その場合はメモリ節約のため、コンポーネントが不要になった際にキャンセルすることが重要です。React はライフサイクルメソッドを提供しており、コンポーネントが生成、破棄されるときに知らせてくれます。次のようなシンプルなミックスインを作ってみましょう。このミックスインのメソッドは簡単な setInterval()
機能を提供し、コンポーネントが破棄されるタイミングで自動的にクリーンアップされます。
var SetIntervalMixin = {
componentWillMount: function() {
this.intervals = [];
},
setInterval: function() {
this.intervals.push(setInterval.apply(null, arguments));
},
componentWillUnmount: function() {
this.intervals.forEach(clearInterval);
}
};
var createReactClass = require('create-react-class');
var TickTock = createReactClass({
mixins: [SetIntervalMixin], // Use the mixin
getInitialState: function() {
return {seconds: 0};
},
componentDidMount: function() {
this.setInterval(this.tick, 1000); // Call a method on the mixin
},
tick: function() {
this.setState({seconds: this.state.seconds + 1});
},
render: function() {
return (
<p>
React has been running for {this.state.seconds} seconds.
</p>
);
}
});
const root = ReactDOM.createRoot(document.getElementById('example'));
root.render(<TickTock />);
コンポーネントが複数のミックスインを使っており、いくつかのミックスインが同じライフサイクルメソッドを定義している場合(例:コンポーネント破棄時に複数のミックスインがクリーンアップ処理をする)、全てのライフサイクルメソッドが呼ばれることが保証されています。ミックスインで定義されているメソッドはミックスインとして列挙された順に実行され、そのあとにコンポーネントのメソッドが呼ばれます。