React学習メモ(練習問題様式)
なぜ練習問題なのか
大学受験の頃によくやっていた方法だから。
よくあるディレクトリ構成
Reactプロジェクトのディレクトリ構成はプロジェクトの規模や用途によって異なる場合がありますが、一般的に以下のような基本的な構成が用いられます:
/public: 静的ファイル(HTML, CSS, images, etc.)を格納するディレクトリ。ここにあるファイルはビルド時にそのまま出力される。
/src: ソースコードを格納するディレクトリ。Reactコンポーネント、テストファイル、スタイルシート、ユーティリティ関数などが含まれる。
/components: 再利用可能なUIコンポーネントを格納。
/pages: アプリケーションの各ページに対応するコンポーネントを格納。
/hooks: カスタムフックを格納。
/utils: ヘルパー関数やユーティリティ関数を格納。
/assets: 画像やフォントなどのアセットを格納。
/styles: 共通のスタイルシートやCSSモジュールを格納。
/node_modules: プロジェクトの依存関係(ライブラリやフレームワークなど)がインストールされるディレクトリ。
package.json: プロジェクトのメタデータや依存関係、スクリプトが定義されたファイル。
Reactフックとは何か?
Reactフックは、関数コンポーネントで状態や様々なReactの機能を使えるようにするための特別な関数です。以前は、Reactの多くの機能を使うには「クラスコンポーネント」と呼ばれる形式を使用する必要がありましたが、フックの導入により、よりシンプルな「関数コンポーネント」でも同様の機能を利用できるようになりました。
たとえば、useState はコンポーネントに状態(データ)を持たせることができ、「このボタンを何回押したか?」というカウントを記録するのに使います。useEffect はデータの取得や購読解除といった「副作用」の処理を行うために使われ、例えばウェブページが表示されたときにサーバーからデータを取得するといったことができます。useContext や useReducer など他にも多くのフックがあり、これらを利用することで、関数コンポーネントで複雑な機能を簡単に実装することができます。
フックを使うことで、コードが読みやすく、管理しやすいものになり、Reactアプリケーションの開発がより効率的かつ効果的に行えるようになります。
useStateの役割と動きについて教えてください
useState はReactの状態管理フックであり、関数コンポーネントでローカル状態を持つために使用されます。このフックを使用すると、状態の値とその状態を更新するための関数がペアで提供されます。例えば、const [count, setCount] = useState(0); とすると、count が状態の値、setCount がその状態を更新する関数です。setCount を呼び出すことで、コンポーネントは再レンダリングされ、新しい状態値が反映されます。
useEffectの役割と動きについて教えてください
useEffect はReactの副作用(サイドエフェクト)を扱うフックで、データの取得、購読の設定、手動でのDOMの変更など、レンダリング結果に影響を与える操作を実行するために使用されます。このフックは、コンポーネントのレンダリング後に実行される関数を指定することができます。useEffect はデフォルトで毎レンダー後に実行されますが、依存配列を第二引数として渡すことで、特定の値の変更時のみに実行されるよう制御できます。例えば、useEffect(() => { console.log('Updated'); }, [count]); は count の値が変わるたびに実行されます。
Reactにおける「副作用」の具体例を教えてください
Reactにおける「副作用」とは、コンポーネントの主要な出力(レンダリング)とは直接関連しない操作のことです。具体的な例としては、以下のものがあります:
データフェッチング: APIからデータを取得し、コンポーネントの状態にセットする。
購読の設定と解除: WebSocketやイベントリスナーのような外部データソースへの購読の設定と解除。
手動でのDOMの更新: コンポーネント外でのDOM操作や、外部JavaScriptライブラリの利用。
配列をループ処理でJSX内で使う場合にkeyを指定する理由は?
Reactがコンポーネントや要素のリストを効率的に再レンダリングするためには、各要素が独自の識別子である key プロパティが必要です。key を提供することで、Reactはリスト内の各要素を一意に識別し、データが変更された際にどの要素が変更、追加、削除されたのかを迅速に判断し、必要な部分のみを効率的に更新することができます。このプロセスにより、パフォーマンスが向上し、予期しないバグ(リストの順序が変わる等)の発生を防ぐことができます。
関数型プログラミングの特徴とメリットは?
関数型プログラミング(Functional Programming, FP)は、プログラムを純粋関数の合成として構築するプログラミングパラダイムです。以下はその主な特徴とメリットです:
特徴:
- 不変性(Immutability): データは変更されず、新しいデータが必要な場合は新しいデータ構造が作成される。
- 純粋関数(Pure functions): 同じ引数に対して常に同じ結果を返し、副作用がない関数。
- 高階関数(Higher-order functions): 関数を引数として受け取り、または関数を結果として返す関数。
- 関数合成(Function composition): 複数の関数を組み合わせて新しい関数を作る技術。
メリット:
- 予測可能性とデバッグの容易さ: 副作用がなく、純粋な関数を使用することでプログラムの振る舞いが予測* しやすくなり、デバッグが容易になる。
- モジュール性と再利用性: 高階関数と関数合成により、コードの再利用性が高まり、モジュール性が向上する。
- テストのしやすさ: 純粋関数は独立しているため、他のコンポーネントに影響を受けずにテストが行える。
JSXとJavaScriptの記述部分の違いは?コメントを書く方法は?
renderメソッドのreturn内のみ、JSXで記述する必要があります。
renderメソッドの、returnの外にはJavaScriptを記述できます。
JSXとJSの主な違いは、JSXはHTMLに似た構文を使用してReact要素を作成するのに対し、JSはJavaScriptの標準的な構文を使用します。JSXはビルド時にJavaScriptに変換されるため、開発者はUIを直感的に記述できます。
JavaScript のコードの中に <ul> や <li> が書けるようになっています。この HTML のタグを書けるように JavaScript を拡張してサポートしているのが JSX です。
コメントの書き方:
- JavaScript: 通常のJavaScriptコード内では // で行コメントを、/* */ でブロックコメントを書きます。
- JSX: JSX内でコメントを書くには {/* コメント内容 */} の形式を使います。この形式でコメントを記述すると、出力されるHTMLには含まれません。
コンポーネントのテンプレートを作成するコマンド
rafce
forEachとmap関数の違いは?
forEachとmapはJavaScriptの配列に対して使われる二つの異なるメソッドで、それぞれ異なる目的と結果を持ちます。
forEach:
forEachメソッドは配列の各要素に対して指定された処理を実行しますが、新しい配列を返しません。
このメソッドは副作用を持つ操作に適しており、例えば配列の各要素をコンソールに表示する場合などに使用されます。
戻り値はundefinedです。
例:
const numbers = [1, 2, 3];
numbers.forEach(number => console.log(number * 2)); // 2, 4, 6 を出力
map:
mapメソッドも配列の各要素に対して処理を実行しますが、各要素に対して処理された結果を新しい配列として返します。
このメソッドは元の配列を変更せず、処理の結果をもたらす新しい配列を生成することで、データの不変性を保持するのに適しています。
戻り値は新しい配列です。
例:
const numbers = [1, 2, 3];
const doubled = numbers.map(number => number * 2); // [2, 4, 6] を返す
コンポーネントを使うメリットを、バニラJSと比較して説明して
コンポーネントは簡単にコピペ(別ファイルで各所に使い回し)出来、Vanila JAVASCRIPTの様に、データベースからデータをfetchし、querySelector()でDOMエレメントを抽出し、target.addEventListener()でイベントを追加し、createChild()やappendChildでHTMLエレメントを追加しつつ、動的データをループで流していくみたいな作業を一個一個のエレメントに対してやる必要がないのである。
各コンポーネントは、すでに構造(HTML)、UI(CSS)、機能(JavaScript)をそれぞれで独立して保持している。
「なるべくuseEffectを使わない」という時代の潮流はなぜ?
React 18の導入により、新しい機能であるuseSyncExternalStoreやReactのConcurrent Modeが導入されました。これらの機能により、UIの同期性を高め、副作用の管理をより直感的に行えるようになりました。useEffectは副作用を扱うためのフックですが、不適切に使用されると予測不能なバグやパフォーマンスの問題を引き起こすことがあります。特に、副作用の依存関係を正確に管理しないと、無限ループや不要な再計算が発生することがあります。このため、「なるべくuseEffectを使わない」という潮流が生まれ、状態の同期やデータフェッチングをより効果的に行う手法が模索されています。
「API叩いてresのlistを表示するぐらい」とは?
API繋ぎ込み 0から作って!はないかもですが、すでにいくつかのAPIと繋ぎ込みがされている中で「既存のコードの横展開でいけるはずだからやってみて~」というのは大いにあり得ます。 大袈裟に考えなくてもいいので、単純にAPI叩いてresのlistを表示するぐらいの感じでokです。
Create React Appをカレントディレクトリに直接展開するには?
$ npx create-react-app .
app.jsとindex.jsの役割
index.js: 一般的に、Reactアプリケーションのエントリーポイントです。ReactDOM.render()を使ってAppコンポーネント(または他のルートコンポーネント)をHTMLのDOMにマウントする役割を持っています。また、必要なグローバルスタイルや外部ライブラリの設定もここで行われます。
App.js: アプリケーションのルートコンポーネントであり、アプリケーション内の主要なビュー構造やルーティングの設定が含まれます。他のUIコンポーネントはこのAppコンポーネントの中で呼び出され、組み合わされます。
map関数に置換してください
<h1>ポケモン図鑑</h1>
<div className='pokemon-container'>
<div className='all-container'>
- <PokemonThumbnails
- id={pokemon[0].id}
- name={pokemonNames[0]}
- image={pokemon[0].image}
- type={pokemon[0].type} />
- <PokemonThumbnails
- id={pokemon[1].id}
- name={pokemonNames[1]}
- image={pokemon[1].image}
- type={pokemon[1].type} />
- <PokemonThumbnails
- id={pokemon[2].id}
- name={pokemonNames[2]}
- image={pokemon[2].image}
- type={pokemon[2].type} />
+ {pokemons.map((pokemon, index) => (
+ <PokemonThumbnails
+ id={pokemon.id}
+ name={pokemonNames[index]}
+ image={pokemon.image}
+ type={pokemon.type}
+ key={index}
+ />
+ ))}
</div>
</div>
STEP7 個
ボタンをクリックするとカウントが増えるコンポーネントを書いて
ユーザーがボタンをクリックしたときに、表示名が切り替わるようにするには、イベントとstateという2つの武器が必要なのじゃ。
import React, { useState } from "react";
export const CounterComponent = () => {
// state を追加
const [count, setCount] = useState(0);
return (
<div>
<p>{count}</p>
{/* クリックすると count が増える関数 */}
<button
onClick={() => {
setCount(count + 1);
}}
>
クリック
</button>
</div>
);
};
更新するための関数は「set○○」といった形式にする場合が多いです。ステートには数値や文字列、オブジェクトなど、任意の値を初期値として渡せます。
useEffectの落とし穴について教えてください
import React, { useEffect, useState } from 'react';
export const Counter => {
const [count, setCount] = useState(0);
// ステータスが変更されるたびに関数を実行させる。
useEffect(() => {
setCount(count + 1);
}, [count]);
return <div>{count}</div>;
}
依存関係にある値が更新されるごとにuseEffectが呼び出されています。上記の関数ではcountを第二引数にセットしていますが、この値はuseEffectの関数が実行されるたびに更新されます。そのため、
useEffectの処理を実行
countの数値を更新
countが更新されたのでuseEffectが再度実行
…という無限ループに陥ってしまうのです。対策として、useEffectの第二引数を空にします。第二引数を空にすると、マウント・アンマウント時にしか呼ばれなくなります。
import React, { useEffect, useState } from 'react';
export const Counter => {
const [count, setCount] = useState(0);
// 第二引数を空にする
useEffect(() => {
setCount(count + 1);
}, []);
return <div>{count}</div>;
}
クラスコンポーネントから関数コンポーネントへと移ったのはいつ頃?
2018年ごろ。
2019年〜 Hooks APIの登場
昨今のReactコンポーネントの主流はクラスコンポーネントから関数コンポーネントに移り変わってきています。 理由としては、やはりHooks APIの登場がとても大きいでしょう。コンポーネントの責任分担をシンプルに行えるため、テストのしやすさも向上しています。
propsとstateの違いは何ですか?
Reactにおいて、props(プロパティ)とstateはコンポーネントのデータを管理するための二つの主要な概念ですが、それぞれ異なる役割と特性を持っています。propsは親コンポーネントから子コンポーネントに渡されるデータで、主にコンポーネントの再利用性を高めるために使用されます。一方、stateはコンポーネント内部で管理されるデータで、主にユーザーのインタラクションやデータフェッチングによって変更される動的な情報を保持します。propsはコンポーネントが受け取るパラメータのようなもので、コンポーネント外から与えられ変更できない一方、stateはコンポーネント内で完全に制御され、更新が可能です。
ライフサイクルメソッドとは何ですか?
ライフサイクルメソッドは、Reactのクラスコンポーネントにおいて、コンポーネントの生成から破棄までの各段階で呼び出される特別なメソッドです。これにより、特定のタイミングで必要なコードを実行することができます。主なライフサイクルメソッドには、マウント時のcomponentDidMount、アップデート時のcomponentDidUpdate、アンマウント時のcomponentWillUnmountがあります。これらを利用することで、APIからのデータフェッチ、タイマーの設定、外部ライブラリの連携などが可能になります。
Reactでのイベントハンドリングについて説明してください。
Reactでは、イベントをハンドルするためにJSXを使用してイベントハンドラーを直接指定します。Reactのイベントハンドリングは、JavaScriptのそれと似ていますが、いくつかの違いがあります。例えば、Reactのイベントハンドラーはキャメルケースで命名され(onClick, onChangeなど)、文字列ではなく関数としてイベントハンドラを渡します。イベントハンドラ関数内でthisを使う場合、通常はコンストラクタ内でその関数をコンポーネントのインスタンスにバインドする必要がありますが、関数型コンポーネントやアロー関数を使用することでこの手間を省くことができます。
条件付きレンダリングとは何ですか?
条件付きレンダリングとは、特定の条件に基づいて異なるコンポーネントや要素を表示するReactのテクニックです。JavaScriptの条件演算子(ifや三項演算子など)を使用して、コンポーネントのrenderメソッド内や関数型コンポーネント内で条件に応じたUIを出力します。これは例えば、ユーザーがログインしているかどうかによって異なるナビゲーションメニューを表示する場合などに便利です。
Reactでのリストとキーについて説明してください。
Reactでリストをレンダリングする際には、各リストアイテムに一意のkeyプロップを提供する必要があります。keyはReactがどのアイテムが変更、追加、または削除されたかを識別するのを助け、効率的な再レンダリングを実現します。通常、データの一意なIDをkeyとして使用しますが、一意なIDが存在しない場合は、アイテムのインデックスを最後の手段として使用することがあります。keyは兄弟間で一意である必要があり、グローバルに一意である必要はありません。これにより、パフォーマンスが向上し、アプリケーションの動作が予測可能になります。
コンポーネントのパフォーマンス最適化について説明してください。
Reactでのコンポーネントのパフォーマンス最適化はアプリケーションの応答性と効率を向上させるために非常に重要です。不必要なレンダリングを減らすことが主な目標で、これはコンポーネントがプロップスやステートに基づいて不要に再レンダリングされるのを防ぎます。React.memoやuseMemoなどのツールを使用してコンポーネントの出力がプロップスによって決定され、それらが変わらない限り再計算を避けることができます。また、大きなリストや複雑なUIを持つ場合、仮想化技術を使用して現在画面上に表示されている要素のみをレンダリングし、パフォーマンスを向上させることができます。
コンテキスト(Context)とは何ですか?
ReactのContext APIはコンポーネントツリー全体にわたってデータを共有する方法を提供し、中間のコンポーネントを通じてプロップスを渡す必要を排除します。例えば、ユーザーの認証状態やテーマ設定など、アプリケーションの多くの部分でアクセスが必要なデータをContextを使って簡単に渡すことができます。これにより、コードの再利用性が向上し、プロップドリリングの問題を解決することができます。
フォームの処理をReactで行う方法について説明してください。
Reactではフォームの処理を柔軟に行うことができ、主に制御コンポーネントと非制御コンポーネントの二つのアプローチがあります。制御コンポーネントでは、各入力フィールドの状態をReactのstateで管理し、onChangeハンドラを通じてその状態を更新します。これにより、フォームの状態が常にReactの状態と同期され、より精密な制御が可能になります。非制御コンポーネントでは、フォーム要素にrefを使用して直接アクセスし、React外でフォームの状態を管理します。これはフォームのデータを扱う際により少ないコードで済む場合があります。
Reactのテストについて知っていることを述べてください
Reactのテストはアプリケーションが期待通りに動作することを保証するために不可欠です。ユニットテストは小さな単位でコンポーネントの動作を確認し、統合テストは複数のコンポーネントが互いに正しく動作するかをテストします。エンドツーエンドテストは、ユーザーの操作を模倣してアプリケーション全体が期待どおりに動作するかを確認します。JestやReact Testing Library、Cypressなどのツールが広く使用されており、開発プロセスにおいてテストを効率的に組み込むことができます。
高階コンポーネント(Higher-Order Component, HOC)とは何ですか?
高階コンポーネント(HOC)は、コンポーネントロジックの再利用を目的とした高度なテクニックです。HOCは既存のコンポーネントを引数として受け取り、新しい機能を追加した新しいコンポーネントを生成します。これにより、複数のコンポーネント間で共通の機能を共有し、コードの重複を減らすことができます。例としては、データフェッチングやアクセス制御、スタイリングの適用などがあり、コンポーネントの抽象化と再利用を助けます。
React.memoとは何で、どのような場合に使用するべきですか?
React.memoは高階コンポーネントであり、プロップスの変更にのみ反応してコンポーネントを再レンダリングする仕組みを提供します。これは、コンポーネントのプロップスが同じであれば、Reactによる不必要なレンダリングを防ぎ、パフォーマンスを向上させるために使用されます。特に、頻繁に更新が行われる大規模なアプリケーションにおいて、不必要なレンダリングを抑制することで応答性と効率を高めることができます。
React.memoは純粋コンポーネントに最適で、内部状態やサイドエフェクトが関与しない場合、またはプロップスに基づいてのみ描画が行われる場合に特に有効です。ただし、比較処理自体が高コストである場合や、コンポーネントが常にプロップス変更によって更新される場合には、React.memoを使用することが逆効果となることもありますので、使用する際には注意が必要です。
React.Fragmentとは何で、なぜ使用するのですか?
React.Fragmentは、複数の要素をグループ化して返す際に、余分なDOMノードを追加しないためのコンポーネントです。通常、JSXでは一つの要素しか返すことができないため、複数の要素を返す場合は何らかの要素でラップする必要がありますが、これが余計なdivなどの要素を追加してしまうことがあります。React.Fragmentを使用することで、この余分な要素の挿入を防ぎつつ、複数の子要素を一つのグループとして返すことができます。
これは、特にCSSレイアウトを崩さずにコンポーネントを構築したい場合や、不要なDOM要素の追加を避けたい場合に有用です。また、短い構文である空のタグ(<>と</>)を使用して、より簡潔に記述することも可能です。
Discussion
失礼します。
とありますが、そこは微妙に異なっています。
.jsx
(または.tsx
など) ファイルの中では、全ての場所でJSX 記法 (<Comp />
) を使えます。なぜなら、 JSX は、
jsx
jsxs
関数の呼び出し、すなわち React 要素を生成する《式》に単純に変換されるからです。(つまり、JSX 記法は、JS のプログラムの中に埋め込まれた単なる《式》です。)なので、普通は return 文の中で書かれるのがほとんどですが、仕様上は、return 文の中かどうかに関係なく、《式》を書ける場所であればどこでも、JSX 記法の《式》が
jsx
jsxs
関数に変換されます。