前回の記事では、propsについて勉強できました。
前回の記事でも冒頭記述したように、復習(忘れないように)でもう一度記述しようと思います。
Props(プロップス):
props
は、親コンポーネントから子コンポーネントにデータを渡すために使用される。props
は読み取り専用であり、コンポーネント内で変更することはできない。props
は外部から渡されるため、コンポーネント内部では不変となる。- 親コンポーネントが子コンポーネントにデータを渡すためのメカニズムとして使用され、コンポーネント間のデータの受け渡しに便利。
気になったのが、stateも同じデータを管理するものだったと思うので、
State(ステート):
state
は、コンポーネント内部で管理されるデータの状態を表現する。state
はコンポーネントによって変更可能であり、setState
メソッドを使用して更新することができる。state
はコンポーネントに固有であり、そのコンポーネント自体が保持するデータになる。state
の変更によって、Reactはコンポーネントを再レンダリングして、変更をUIに反映する。
propsとstateの違いとしては、
props
は外部から渡される読み取り専用のデータであり、コンポーネント内で変更することはできないようです。一方、state
はコンポーネント自体が管理する可変のデータであり、コンポーネント内で変更が可能となるようです。
例えば、親コンポーネントから子コンポーネントにユーザー名を渡す場合、props
を使用するようでした。ユーザーがボタンをクリックしたときに表示されるテキストを変更する場合、state
を使用してコードを記述していました。
復習ができたところで、今回は、Stateについての記事を書こうと思います。
ステートフルコンポーネントを作成する
自分でまとめた上記の説明プラス学んだことを記述してみます。
state (状態、ステート) は、アプリケーションが認識する必要のあるデータで構成され、時間とともに変化する可能性があります。 アプリでは通常、必要に応じて状態の変化に応答し、更新された UI を表示します。 React は、最新のウェブアプリケーションの状態管理に適したソリューションを備えています。
https://www.freecodecamp.org/japanese/learn/front-end-development-libraries/react/create-a-stateful-component
React コンポーネントで state を作成するには、
https://www.freecodecamp.org/japanese/learn/front-end-development-libraries/react/create-a-stateful-componentconstructor
のコンポーネントクラスでstate
プロパティを宣言します。 これにより、コンポーネントが作成時にstate
で初期化されます。state
プロパティは JavaScript のobject
に設定する必要があります。
下記が、stateプロパティでのオブジェクト設定
this.state = {
}
コンポーネントが存在している間は、
https://www.freecodecamp.org/japanese/learn/front-end-development-libraries/react/create-a-stateful-componentstate
オブジェクトにアクセスすることができます。 更新したり、UI にレンダーしたり、props として子コンポーネントに渡したりすることができます。state
オブジェクトは必要に応じて単純なものにも複雑なものにもすることができます。 こうしたstate
を作成するには、React.Component
を拡張してクラスコンポーネントを作成する必要があります。
ユーザーインターフェイスに state をレンダーする
コンポーネントの初期状態を定義したら、レンダーされる UI に、そのコンポーネントの任意の部分を表示することができました。
コンポーネントがステートフルの場合は、コンポーネントから常に自身の render()
メソッドの中で state
のデータにアクセスできるようです。 データへのアクセスには this.state
を使用できました。
render メソッドの return
の中で state 値にアクセスする場合は、値を中括弧で囲む必要があるようです。
React では、仮想 DOM と呼ばれるものを使用して、見えないところで変更を追跡しているようです。 state のデータが更新されると、データを prop として受け取った子コンポーネントを含めて、そのデータを使用しているコンポーネントの再レンダーをトリガーするようです。
実際の DOM も更新しますが、必要な場合に限られるようでした。
つまり、DOM の変更を気にする必要はない、ということらしいです。
単に UI をどのように表示させるかを宣言するだけみたいです。
また、あるコンポーネントをステートフルにした場合、他のコンポーネントはその state
を認識しないことに注意しないといけないようです。
state データを props
として子コンポーネントに渡さない限り、state
は完全にカプセル化されるか、またはそのコンポーネントに対してローカルになるから見たいです。state
のカプセル化という考え方はとても重要なようです。
なぜなら、特定のロジックを記述して、そのロジックをコード内の 1 か所に閉じ込めて分離しておけるからです。
まとめると、
- stateは、1つのコンポーネント内でしか、利用できないということ。
- 仮に他のコンポーネントでも使用したい場合は、propsを使用して子コンポーネントとしてデータを渡す必要がある。
別の方法でユーザーインターフェイスに state をレンダーする
別の方法でコンポーネントの state
にアクセスすることもできるそうです。render()
メソッドで、return
ステートメントの前に直接、JavaScript を記述することができました。 たとえば、関数を宣言したり、state
や props
のデータにアクセスしたり、そのデータに対して計算を実行したりできます。
任意のデータを変数に割り当てて、return
ステートメントでアクセスすることができます。
returnメソッドより上では、JavaScript を直接記述できるので、この参照を中括弧で囲む必要はありません。
this.setState を使用して state を設定する
ここでは、コンポーネントの state
を変更する方法を学びました。
React には、コンポーネントの state
を更新するための setState
というメソッドが用意されているようです。setState
メソッドはコンポーネントクラスの中で this.setState()
のように呼び出し、キーと値のペアを持つオブジェクトを渡します。
キーは state のプロパティであり、値は更新された state データです。 たとえば、username
を state に保存していて、それを更新したい場合は、次のようにします。
this.setState({
username: 'Lewis'
});
また、React ではパフォーマンスを向上させるために複数の state の更新がバッチ処理されることがあります。 このため、setState
メソッドによる state の更新が非同期になる可能性があります。 この問題を回避する方法として、setState
メソッドの代わりとなる構文があります。 必要になることはめったにありませんが、覚えておくと役に立ちます。
また、React ではパフォーマンスを向上させるために複数の state の更新がバッチ処理されることがあります。 このため、
setState
メソッドによる state の更新が非同期になる可能性があります。 この問題を回避する方法として、setState
メソッドの代わりとなる構文があります。 必要になることはめったにありませんが、覚えておくと役に立ちます。詳細については freeCodeCamp の React に関する記事を参照してください。
https://www.freecodecamp.org/japanese/learn/front-end-development-libraries/react/set-state-with-this-setstate
と書かれていたのですが、よくわからなかったので、調べてみたところ。
下記のようなことがわかりました。
setState メソッドの代わりに使用できる構文として、関数形式の setState を利用する方法があ流ようです。この方法を使用することで、state の更新が非同期になる可能性を回避することができます。
通常の setState メソッドでは、state の更新は非同期で行われるため、連続して複数回の状態更新を行う場合に予期しない結果が生じる可能性があるようです。これは、React がパフォーマンスの最適化のために、複数の state 更新をまとめてバッチ処理するためのようです。
関数形式の setState を使用すると、更新する状態を前の状態に依存させることができます。これにより、最新の状態を保証しながら連続して状態更新を行うことができます。
以下は、関数形式の setState の例です:
this.setState((prevState) => {
return { count: prevState.count + 1 };
});
この例では、prevState を引数として受け取り、更新後の状態を返す関数を渡しています。この関数内で状態の更新を行うことができます。React はこの関数を同期的に実行し、前の状態を最新の状態として扱うようです。
関数形式の setState を使用することで、連続して状態の更新を行う際に正確な結果を得ることができきるようです。ただし、注意点として、関数形式の setState は非同期ではなくなるため、パフォーマンス上の理由で状態の更新がバッチ処理されることはありません。そのため、特定のタイミングでの最新の状態が必要な場合には、コールバックや useEffect の依存リストなどの他の手法を検討する必要があるそうです。
ちなみに、最近のReactでは、useEffectがよく使われているそうでした。
useEffectフックは、コンポーネントのライフサイクルイベントや副作用を扱うためのフックです。
従来のReactクラスコンポーネントでは、※ライフサイクルメソッド(componentDidMount、componentDidUpdate、componentWillUnmountなど)を使用して副作用やデータの取得を行っていました。しかし、関数コンポーネントではライフサイクルメソッドが使用できないため、代わりにuseEffectフックを使用することが推奨されています。
useEffectフックは、コンポーネントがレンダリングされた後に実行され、コンポーネントが再レンダリングされるたびにも実行されます。主な目的は、以下のような副作用を処理することです:
- データの取得やAPIの呼び出し
- イベントリスナーの設定や解除
- タイマーの設定や解除
- 外部ライブラリの初期化やクリーンアップ
useEffectフックは、第1引数に副作用を含む関数を受け取ります。この関数は副作用を実行し、必要な場合にはクリーンアップ関数を返すこともできます。
以下は、useEffectフックの基本的な使用例です:
import React, { useEffect } from 'react';
function MyComponent() {
useEffect(() => {
// 副作用の処理
return () => {
// クリーンアップ関数(必要な場合)
};
}, []); // 依存リスト(変更を監視する状態)
// コンポーネントの描画
}
第2引数に依存リストを指定することで、特定の状態の変更にのみ反応するように制御することもできます。依存リストが空の場合、副作用は最初のマウント時にのみ実行され、コンポーネントのアンマウント時にクリーンアップ関数が呼び出されます。
useEffectフックは、コンポーネントの副作用の管理やリソースの解放など、様々なシナリオで役立ちます。適切に使用することで、コンポーネントのパフォーマンスやメモリリークの問題を回避しながら、柔軟で効率的なコードを記述することができます。
※ライフサイクルメソッド:Reactコンポーネントの特定の時点で呼び出されるメソッドのことです。これらのメソッドを使用することで、コンポーネントの作成、更新、破棄などの異なるフェーズでカスタムの動作や処理を追加することができるようです。(ライフサイクルメソッドは、最近はあまり使われないそうです。)
クラスメソッドに ‘this’ をバインドする
state
の設定と更新に加えて、コンポーネントクラスのメソッドを定義することもできるようです。
クラスメソッドでは通常、メソッドのスコープ内でクラスのプロパティ (state
や props
など) にアクセスできるように、this
キーワードを使用する必要があ流ようです。
いくつかの方法でクラスメソッドから this
にアクセスすることができます。
よく使用される方法として、コンストラクターで this
を明示的にバインドすることでできるようです。この場合、コンポーネントの初期化時に this
がクラスメソッドにバインドされます。
バインド:
バインド(Bind)は、JavaScriptにおいて、関数と特定のオブジェクトを結びつけることを指すようです。これにより、関数内の this
キーワードが特定のオブジェクトを参照するようになります。
通常、関数内で this
を使用する場合、その関数がどのオブジェクトに属しているかによって this
の値が変わります。しかし、関数を別のコンテキストで使用する場合や、イベントハンドラーとして使用する場合には、this
の値が予期しないものになることがあるようです。
これを回避するために、bind
メソッドを使用して関数を特定のオブジェクトにバインドすることができるようです。bind
メソッドは、関数が呼び出されたときに this
が指すべきオブジェクトを明示的に指定します。
以下が、バインドの例です。
const person = {
name: 'John',
sayHello: function() {
console.log(`Hello, ${this.name}!`);
}
};
const sayHello = person.sayHello.bind(person);
sayHello(); // "Hello, John!"
この例では、person
オブジェクト内の sayHello
メソッドを bind
メソッドを使って person
オブジェクトにバインドしました。これにより、sayHello
関数が呼び出されたときに this
が person
オブジェクトを参照するようになります。
bind
メソッドを使用することで、関数が正しいコンテキストで実行されることが保証されます。これにより、関数を他のコンテキストで使用する場合や、クラスコンポーネントのイベントハンドラーとして使用する場合などで便利だそうです。
state を使用して要素を切り替える
stateを更新する際に、更新する前のstateの値を知る必要がありました。
ただ、stateの更新が非同期であった場合、Reactが複数のsetState関数の呼び出しを単一に更新するようになります。(バッチ処理の影響)
なので、次の値を計算する際に、this.state や tihs.props を使用した前の値に頼れなくなります。
そのため、
this.setState({
counter: this.state.counter + this.props.increment
});
上記のコードの場合、
this.state
とthis.props
の値は現在の値を参照します。しかし、非同期的な更新のため、このコードが実行された後、this.state
やthis.props
が変更されている可能性があります。そのため、意図した通りに状態を更新することができない場合があります。
つまり、上記のような、コードは使用しないようになっています。
では、代わりにどうするのか?
stateやpropsにアクセスできる関数をstateに渡すことで解決できるようです。
どういうことかというと、
コールバック関数を使用すると、
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
this.setState
の引数として渡された関数は、最新の状態とプロパティを参照することができます。コールバック関数内では、state
パラメータは現在の状態を、props
パラメータは現在のプロパティを表します。そのため、常に最新の値を使用して状態を計算することができます。
このようにコールバック関数を使用することで、非同期の状態更新に対してより正確に対応することができるようになるからだそうです。
シンプルなカウンターを記述する
ここで、今までのまとめのような感じで課題がありました。
問題は、
state
で count
の値を追跡する Counter
コンポーネントがあります。 2 つのボタンがあり、increment()
メソッドと decrement()
メソッドを呼び出します。 対応するボタンがクリックされたときにカウンターの値が 1 ずつ増加または減少するように、これらのメソッドを記述してください。 また、リセットボタンをクリックしたときにカウントを 0 に設定する reset()
メソッドを作成してください。
注: ボタンの className
は変更しないでください。 また、コンストラクターで新しく作成されるメソッドに必要なバインディングを忘れずに追加してください。
とのことでした。
下記やったことの内容とコードを共に記述しておきます。
※つまずいた点
this.setState
メソッドの引数としてアロー関数を使用する場合、アロー関数がオブジェクトを返すことを示すために、()
で囲むことが一般的なようでした。'()’がないとエラーが出た、、、
以下のコードのところです。:
this.setState((prevState) => (
{ count: prevState.count - 1 }
))
この場合、this.setState
の引数として渡されたアロー関数は、前の状態(prevState
)を受け取り、新しい状態をオブジェクトとして返しています。オブジェクトは波括弧 {}
で囲まれており、その中に新しい状態のプロパティであるcount
とその値を定義しています。
this.setState
メソッドは、この返されたオブジェクトを使用して状態を更新します。
()
で囲まれたオブジェクトは、アロー関数の本体であることを明示的に示しています。これにより、オブジェクトを返すことが意図されていることを明確にします。
制御された入力を作成する
お問い合わせフォームなので、ユーザーが入力するところで制御可能なフォームにする際に今回勉強したことが役に立つそうです。
アプリケーションによっては、レンダーされた UI と
https://www.freecodecamp.org/japanese/learn/front-end-development-libraries/react/create-a-controlled-inputstate
との間でもっと複雑なやり取りをする場合があります。 たとえば、input
やtextarea
などのテキスト入力のフォームコントロール要素は、DOM 内ではユーザータイプとして独自の状態を維持します。 React では、こうしたミュータブルな状態の扱いを React コンポーネントのstate
に移すことができます。 ユーザーの入力はアプリケーションのstate
の一部となり、その入力フィールドの値は React によって制御されます。 通常は、ユーザー入力が可能な入力フィールドを持つ React コンポーネントがある場合、それは制御された入力フォームになります。
課題としては、
コードエディターに、制御された input
要素を作成するための ControlledInput
というコンポーネントのスケルトンがあります。 コンポーネントの state
は、空文字列を保持する input
プロパティですでに初期化されています。 この値は、ユーザーが input
フィールドに入力するテキストを表します。
まず、event
というパラメーターを持つ handleChange()
というメソッドを作成してください。 このメソッドが呼び出されると、input
要素からのテキスト文字列を含む event
オブジェクトを受け取ります。 この文字列にはメソッドの中で event.target.value
を使用してアクセスできます。 コンポーネントの state
の input
プロパティを、この新しい文字列に更新してください。
render
メソッドで、h4
タグの上に input
要素を作成してください。 コンポーネントの state
の input
プロパティと等しい value
属性を追加してください。 そして、onChange()
イベントハンドラーを追加して handleChange()
メソッドに設定してください。
入力ボックスに入力すると、そのテキストは、ローカルの state
の input
プロパティとして設定された handleChange()
メソッドによって処理され、ページ上の input
ボックスの値としてレンダーされます。 コンポーネントの state
は、入力データに関して単一の信頼できる情報源になります。
最後に、必要なバインディングを忘れずにコンストラクターに追加してください。
下記がそのコードになります、
「スケルトン」とは、デザインやレイアウトのフレームワークの一部として使用される、コンテンツがない状態のプレースホルダーのことを指すようです。スケルトンは、Webページやモバイルアプリのローディングや遅延読み込み時に、ユーザーに視覚的なフィードバックを提供するために使用されるようです。
※気になったところ
handleChange関数の第一引数eventって必要なのかどうか?
handleChange
関数の第一引数としてevent
が必要なのは、イベントハンドラとして機能するためです。Reactでは、イベントハンドラ関数には通常、イベントオブジェクトが渡されます。
<input>
要素にonChange
イベントが発生したとき、handleChange
関数が呼び出されます。このとき、event
オブジェクトはそのイベントに関連する情報を保持しており、event.target.value
を使用することで入力フィールドの値にアクセスできます。
具体的には、以下の部分です:
handleChange = (event) => {
this.setState((prevState) => ({
input: event.target.value
}));
}
event.target.value
は、イベントが発生した要素の値を取得するために使用されます。input
要素の値が変更されるたびに、新しい値がevent.target.value
として取得され、それがinput
という状態のプロパティに設定されます。
そのため、event
引数はhandleChange
関数内で使用され、入力フィールドの値を取得するために必要となります。
jsでも同様だったかどうか?
JavaScriptでも同様の概念が適用されます。Reactのイベントハンドラ関数には、通常、イベントオブジェクトが渡されます。JavaScriptのイベントモデルでは、イベントハンドラ関数が呼び出されるときに、イベントオブジェクトが自動的に渡されるようになっています。
例えば、以下のようなJavaScriptのイベントハンドラ関数を考えてみましょう:
function handleChange(event) {
console.log(event.target.value);
}
この場合、event
オブジェクトはイベントが発生したときの情報を保持しており、event.target.value
を使用して入力フィールドの値にアクセスできます。
Reactの場合と同様に、JavaScriptのイベントハンドラ関数でも、event.target
はイベントが発生した要素を参照し、event.target.value
はその要素の値を取得します。
したがって、JavaScriptでも同じ原則が適用されるため、event
引数はイベントハンドラ関数内で使用され、要素の値にアクセスするために必要となります。
呼び出す際に引数はいるのか?
JavaScriptのイベントハンドラ関数を呼び出す際には、仮引数を使用することはないようでした。イベントハンドラ関数はイベントが発生した際に自動的に呼び出されるため、明示的な関数呼び出しの際に引数を指定する必要もなかったようです。
以下は一般的な例です:
// イベントハンドラ関数の定義
function handleChange(event) {
console.log(event.target.value);
}
// イベントリスナーに関数を登録
document.getElementById("myInput").addEventListener("input", handleChange);
この例では、handleChange
関数をaddEventListener
メソッドに渡してイベントリスナーとして登録しています。イベントが発生すると、関数が自動的に呼び出され、イベントオブジェクトがevent
として渡されます。
Reactの場合、JSX内でイベントハンドラ関数を指定する場合には、通常はアロー関数や.bind()
メソッドを使用して関数をバインドします。この場合、関数がイベント発生時に自動的に呼び出されるため、明示的な関数呼び出しの際に引数を指定する必要はありません。
例えば、次のように書かれたReactのコードでは、関数のバインドを行っています:
class MyComponent extends React.Component {
handleChange(event) {
console.log(event.target.value);
}
render() {
return (
<input onChange={this.handleChange.bind(this)} />
);
}
}
この例では、onChange
イベントでhandleChange
関数が呼び出されます。関数のバインドが行われるため、関数がイベント発生時に自動的に呼び出され、イベントオブジェクトがevent
として渡されます。
したがって、イベントハンドラ関数を呼び出す際には、通常は引数を指定する必要はありませんでした。イベント発生時に自動的にイベントオブジェクトが渡されていました。
制御されたフォームを作成する
inputやtextAreaなどの要素で内部状態を制御できることを学びました。
なので、通常のHTML form要素を含むフォーム要素にも適用されるようです。
ここで、まとめ課題がありました。
submit ハンドラーを持つ空の form
で設定された MyForm
コンポーネントがあります。 submit ハンドラーはフォームの送信時に呼び出されます。
フォームを送信するボタンはすでに追加してあります。 その type
は submit
に設定されていて、フォームを制御するボタンであることを示しています。 form
に input
要素を追加し、前回のチャレンジのように、その value
と onChange()
属性を設定してください。 次に、handleSubmit
メソッドで、コンポーネントの state プロパティ submit
をローカルの state
の現在の入力値に設定して、メソッドを完成させてください。
注: submit ハンドラーでは、デフォルトのフォーム送信動作が実行されてウェブページが更新されるのを防ぐために、event.preventDefault()
を呼び出す必要もあります。 ここでは簡単のため、更新によるチャレンジコードのリセットを防ぐために、デフォルトの動作は無効になっています。
さらに、form
の後に、コンポーネントの state
の submit
値をレンダーする h1
タグを作成してください。 これで、フォームに入力してボタンをクリックすると (または enter を押すと)、入力がページにレンダーされます。
下記が解答になります。
今回はここまでになります。
最近のReactでは、型宣言はTypeScriptで行うようでした。
また、フォームもある程度こちらで制御できるのもすごく助かります。
本日はここまで〜