はじめに
5日間でReactの基礎を習得する試みの2日目です。2日目は、Reactでよく使われるJSXの記法、クラスコンポーネントと関数コンポーネントについて学びます。
私はC#やPythonを仕事で使っているため、オブジェクト指向の言語的な考え方や、Pythonでの例えを使って理解を進めます。同じような境遇の方の理解の助けになれば幸いです。
JSX
この記事を作るために、ただのJavaScriptの構文でReactのHelloWorldクラスコンポーネントを作ると、以下になります。
class HelloWorld extends React.Component {
render() {
return React.createElement('div', null,
React.createElement('h1', null, 'Hello World'),
React.createElement('h2', null, 'Introduction to HelloWorld'),
React.createElement('p', null, 'Hello Worldプログラムは、新しいプログラミング言語を習得するときの、最初のプログラムです。'),
React.createElement('h2', null, 'Why HelloWorld?'),
React.createElement('p', null, 'Hello Worldはシンプルなため、最初に言語の構造や特徴を理解するのに役立ちます。')
);
}
}
React.createElementを使って書くと、div, h1, h2, pタグの関係や内容が分かりづらくなってしまいます。
JavaScriptでも、HTMLのようにタグを使えれば、もっと見やすいコードになりそうです。
そこで、JSXを使う
JSXとはJavaScriptの拡張で、JavaScript内にHTMLのタグなどのマークアップが使えるようにしてくれます。
さきほどのコンポーネントをJSXを使って書くと、以下のようになります。
class HelloWorld extends React.Component {
render() {
return (
<div>
<h1>Hello World</h1>
<h2>Introduction to HelloWorld</h2>
<p>Hello Worldプログラムは、新しいプログラミング言語を習得するときの、最初のプログラムです。</p>
<h2>Why HelloWorld?</h2>
<p>Hello Worldはシンプルなため、最初に言語の構造や特徴を理解するのに役立ちます。</p>
</div>
);
}
}
このコンポーネントを使って描画するコードが以下です。コンポーネントの内容が非常に見やすくなりました。
HTMLなので、ブラウザがあれば誰でも実行できます。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>React Simple Example</title>
</head>
<body>
<div id="root"></div>
<!-- ReactとReactDOMのライブラリを読み込む -->
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<!-- Babelライブラリを読み込む(ブラウザでJSXを解釈するために必要) -->
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<!-- JSXを使用してJavaScriptを書く-->
<script type="text/babel">
'use strict';
class HelloWorld extends React.Component {
render() {
return (
<div>
<h1>Hello World</h1>
<h2>Introduction to HelloWorld</h2>
<p>Hello Worldプログラムは、新しいプログラミング言語を習得するときの、最初のプログラムです。</p>
<h2>Why HelloWorld?</h2>
<p>Hello Worldはシンプルなため、最初に言語の構造や特徴を理解するのに役立ちます。</p>
</div>
);
}
}
ReactDOM.createRoot(document.getElementById('root'))
.render(<HelloWorld />);
</script>
</body>
</html>
(補足)Babel
上のtest.htmlでは、Babelライブラリを読み込んでいます。これは、JSXをJSに変換してくれるライブラリです。(つまり、HTMLっぽいマークアップの部分を、React.CreateElementに変換してくれる)
Babelについては https://qiita.com/micropig3402/items/064394428791144f5488 の記事がわかりやすいです。
propsとstate
コンポーネントにおいて、重要なのがpropsとstateです。
以下のクラスコンポーネントのコンストラクタを見てください。
class HelloWorld extends React.Component {
constructor(props) {
super(props);
this.state = {
helloValue: 0,
worldValue: 2,
};
}
render() {
return (
<div>
<h1>Hello, World!</h1>
<p>Title: {this.props.title}</p>
<p>Hello Value : {this.state.helloValue}</p>
<p>World Value : {this.state.worldValue}</p>
</div>
);
}
}
props: React.Componentクラスが持つメンバ変数で、プロパティのこと。コンストラクタの引数として使う。読み取り専用で、コンポーネント内では変更ができない。
state: React.Componentクラスが持つメンバ変数で、辞書のように状態を保持するオブジェクト。コンポーネント内からも変更が可能で、値が変わると自動的に再描画される。
上記のコードでは、stateにhelloValueとworldValueの2つの状態を保持させています。また、このコンポーネントを使う側(親コンポーネント)がpropsに"title"というプロパティを与える前提でコードを書いているため、{this.props.title}
というコードが登場します。
描画してみる
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>React Simple Example</title>
</head>
<body>
<div id="root"></div>
<!-- ReactとReactDOMのライブラリを読み込む -->
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<!-- Babelライブラリを読み込む(ブラウザでJSXを解釈するために必要) -->
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<!-- JSXを使用してJavaScriptを書く-->
<script type="text/babel">
'use strict';
class HelloWorld extends React.Component {
constructor(props) {
super(props);
this.state = {
helloValue: 0,
worldValue: 2,
};
}
render() {
return (
<div>
<h1>Hello, World!</h1>
<p>Title: {this.props.title}</p>
<p>Hello Value : {this.state.helloValue}</p>
<p>World Value : {this.state.worldValue}</p>
</div>
);
}
}
ReactDOM.createRoot(document.getElementById('root'))
.render(<HelloWorld title="Hello Title"/>);
</script>
</body>
</html>
.render(<HelloWorld title="Hello Title"/>)
のところがコンポーネントからReact要素を作り出している部分です。<コンポーネント名 与えたいプロパティ名1="" 与えたいプロパティ名2=""...>のように記載することで、コンストラクタの引数であるpropsに値を設定できます。(今回の場合はprops.titleに当たります)
クラスコンポーネントと関数コンポーネント
クラスコンポーネント[あまり使われない]
ここまで、クラスコンポーネントを使って説明してきました。
クラスコンポーネントとは、React.Componentクラスを継承したクラスのことを指します。
class HelloWorld extends React.Component {
constructor(props) {
super(props);
this.state = {
helloValue: 0,
worldValue: 2,
};
}
render() {
return (
<div>
<h1>Hello, World!</h1>
<p>Title: {this.props.title}</p>
<p>Hello Value : {this.state.helloValue}</p>
<p>World Value : {this.state.worldValue}</p>
</div>
);
}
}
C#を使ってきた私にとっては、非常に理解しやすかったのですが、どうやらあまり使われないようです。
というのも、関数コンポーネントというもう一つのコンポーネントを使ったほうが、シンプルで簡潔な構文となり、コードが読みやすくなるそうです。
関数コンポーネント[こっちを使う]
クラスコンポーネントを関数コンポーネントに書き換えると次のようになります。
const HelloWorld = (props) => {
// useStateを使ってstateを定義する
const [helloValue, setHelloValue] = React.useState(0);
const [worldValue, setWorldValue] = React.useState(2);
return (
<div>
<h1>Hello, World!</h1>
<p>Title: {props.title}</p>
<p>Hello Value : {helloValue}</p>
<p>World Value : {worldValue}</p>
</div>
);
}
引数にpropsを取り、返り値にReact要素を持つアロー関数式を書けば、関数コンポーネントとなります。
関数なので、メンバ変数であるstateを保持することができません。その代替え手段として、フックと呼ばれるもののが用意されており、ここではuseStateを使っています。ここは次回勉強します。
(前提知識) 関数式
JavaScriptでは、無名関数が使用できます(Pythonのラムダ式に相当します)。
無名関数を作るためには、関数式を使う方法と、アロー関数式という簡潔な構文を使う方法があります。
// 関数式
const square = function (number) {
return number * number;
}
// アロー関数式
const square = (number) => {
return number * number;
}
ただ "function(引数)" という形にするか、"(引数)=>" という形にするかという違いだけです。
関数コンポーネントの宣言では、アロー関数式がよく使われます。コンポーネントの引数であるpropsを使った、(props) => {return React要素}
の形が基本となるわけです。
イベントハンドリング
コンポーネントでイベントを設定することもできます。
以下では、onClickに関数自身を代入することで、ボタン押下時のイベントを設定しています。ボタンを押すと"Button clicked!"と表示されます。
const HelloWorld = (props) => {
const handleButtonClick = () => {
alert("Button clicked!")
}
return (
<button onClick={handleButtonClick}>ボタン</button>
);
}
propsを使って、親が子コンポーネントのイベントを設定することもできます。
const HelloWorld = (props) => {
// propsにonButtonClickというプロパティが渡される前提で実装
return (
<button onClick={props.onButtonClick}>ボタン</button>
);
}
const handleButtonClick = () => {
alert("Button clicked!")
}
// HelloWorldコンポーネントのpropsのonButtonClickに、handleButtonClickを設定。
ReactDOM.createRoot(document.getElementById('root'))
.render(<HelloWorld onButtonClick={handleButtonClick} />);
他にも色々なイベントハンドラが使えます。 https://qiita.com/P-man_Brown/items/bc7606504d64da42e13e こちらの記事を参考にしてください。
最後に
なじみやすかったクラスコンポーネントから理解し、その後に関数コンポーネントへの移行方法を考えたことで、コンポーネントがかなり理解できたように思います。
次回はフックについて学びます。
何か間違いがあれば、是非コメントを頂けると助かります!
参考文献