Open24

【2023/11更新版】モダンJavaScriptの基本から始める挫折しないためのReact入門 学習ログ

haganenoubikhaganenoubik

DOM、仮想DOM

DOM(ドム:Document Object Model)
HTMLを解釈し、木(ツリー)構造で表現したもの

仮想DOM

DOMを直接指定して書き換える場合
・レンダリングコスト(画面の表示速度)が上がる
・プログラムコードが肥大化すると、どこで何をしているかわからなくなる(コードの複雑化)
といった問題がある。

👉 これらの問題を解決するために作られたのが 仮想DOM

実際のDOMとの差分比較をし、変更箇所のみを実際のDOMに反映することで、DOMへの操作を最小限に抑えることが可能となる。

ReactやVue等のモダンJSフレームワークやライブラリでは仮想DOMが用いられる。

モダンJavaScript

モダンJSって?

明確な定義はないが、主には以下を指す。

  • React、Vue、Angular等の仮想DOMを用いるライブラリ/FWを使用。
    👉 現在では、仮想DOMを用いないSvelteやSolidも含まれる
  • npm/yarn等のパッケージマネージャーを使用
  • 主にES2015(ES6)以降の記法を使用
  • Webpack、Vite等のモジュールバンドラーを使用
  • Babel、SWC等のトランスパイラを使用
haganenoubikhaganenoubik

パッケージマネージャー:npm/yarn

npmやyarnを使用するメリット

・依存関係を意識しなくても勝手に解決してくれる
・チーム内でのパッケージの共有や、バージョン統一が容易
・世界中で公開されているパッケージをコマンド1つで利用可能
・どこから読み込んだものか分かりやすくなる

NPM:パッケージのレジストリ(公開場所)
package.json:設計書的な役割のファイル
package-lock.json・yarn.lock:自動で生成されるファイル。依存関係、バージョンの解決
node_modules:各モジュールの実体(jsファイル等)。サイズが膨大。Githubにはアップしない。

haganenoubikhaganenoubik

モジュールバンドラー・トランスパイラ

開発は効率良く、実行時はうまく変換

モジュールバンドラー

複数のファイル(js/css/image)を1つにまとめてくれるもの。
現在、主流のモジュールバンドラーはwebpack。

開発環境:細かく分けて開発した方が効率的
本番環境:ファイルが分かれていることで、読み込みのパフォーマンスが悪化することがある
👉「開発はファイルを分けて行い、本番用にビルドする時に1つのファイルにまとめる」という思想を実現するために、jsファイルやcssファイル等をまとめてくれるもの。

https://vitejs.dev/
https://zenn.dev/longbridge/articles/93f63e0423785b

トランスパイラ

JSの記法をブラウザで実行できる形に変換してくれるもの。
👉 新しいJSの記法を古い記法に変換してくれる!
現在、主流のトランスパイラはBabel、SWC。

Reactの場合、jsファイルにJSX記法と呼ばれる特殊な書き方も、ブラウザで認識できる形に自動変換してくれる。

haganenoubikhaganenoubik

SPA(Single Page Application)とは

  • SPAでは基本的にHTMLファイルは1つのみ。
  • JSで画面を書き換える(DOMの書き換え)ことで画面遷移等の動きを表現する。

👉従来のWebシステムのように、ページ遷移の際の画面のチラつきをなくし、非同期的に画面更新できる。

haganenoubikhaganenoubik

JSの基礎知識

JSの変数宣言の種類

  • var
  • let
  • const

varでの変数宣言は、モダンJS開発ではほぼ使用されない。

👉const, letという変数宣言の方法が追加された。

letでの変数宣言

・上書きはできる。
・再宣言はできない。

constでの変数宣言

・上書きも再宣言もできない。(厳密な変数宣言)
※constant:定数

haganenoubikhaganenoubik

React開発では結局どれを使うの?

結論:ほぼconstを使う。

Stateで管理せず、処理の中で値を上書きしていくような変数のみletを使う。

haganenoubikhaganenoubik

JSの基礎的な記法

テンプレートリテラル

`${変数}` // $マーク{}をバッククォートで囲む
const name = "ちいかわ"
const age = "6"

const message = `私の名前は${name}です。年齢は${age}歳です。`

console.log(message); //=> 私の名前はちいかわです。年齢は6歳です。

関数定義の記法

従来の関数の定義方法

function 関数名(引数) {
  // 処理内容
}

関数を変数に格納してから実行

const 変数名 = function (引数) {
  // 処理内容
}

アロー関数

const 変数名 = (引数) => { // functionの宣言が不要になり、=>記号で関数を記述する
  // 処理内容
}
アロー関数の省略記法

アロー関数の省略記法

引数が1つの場合は( )を省略できる

const greeting = value => { // 引数が1つなので( )を省略
    return value;
};

console.log(greeting("おはよう")); //=> おはよう

引数が2つ以上の場合は( )は省略不可。

const greeting = (value1, value2) => {

処理を1行で返却する場合は、{ }とreturnを省略できる

const greeting = value => value;

console.log(greeting("おはよう")); //=> おはよう

返却値が複数行の場合は、( )で囲む

const human = (val1, val2) => (
  {
    name: val1,
    age: val2,
  }
)

console.log(human("ちいかわ", 6)); //=> { name: 'ちいかわ', age: 6 }
haganenoubikhaganenoubik

分割代入:{ } [ ]

オブジェクトや配列から値を抽出するための方法。

復習:オブジェクトと配列は違うもの?

オブジェクトと配列は異なる概念だが、どちらも複雑なデータを格納するための構造を提供する。

オブジェクト

オブジェクトは、キーと値のペアで構成されるデータ構造。
これは物事の「属性」や「特性」を表現するのに適している。
例:人物の情報

const person = {
  name: "Alice",
  age: 25,
  isStudent: true
};

ここでは「name」「age」「isStudent」はオブジェクトの「キー」(またはプロパティ名)で、"Alice"、25、true はそれぞれのキーに対応する「値」である。

配列

配列は、要素の順序付きリスト。
これは同一の種類のアイテムの集合を扱うのに適している。
例:数値のリスト、文字列のリスト

const numbers = [1, 2, 3, 4, 5];
const names = ["Alice", "Bob", "Charlie"];

配列の各要素にはインデックス(位置)があり、0から始まる。
例:numbers[0] は 1、names[2] は "Charlie"

オブジェクトと配列の違い まとめ

構造
オブジェクト:キーと値のペアの集合。
配列:順序付きの値のリスト。

アクセス方法
オブジェクトの値にアクセスするには:キーを使う(person.name)。
配列の要素にアクセスするには:インデックスを使う(names[0])。

用途
オブジェクト:異なるタイプのデータを1つにまとめるのに適している。
配列:同じタイプの複数のアイテムを順序付きで格納するのに適している。

JSでは、配列も特別な種類のオブジェクトの一つだが、一般的な使用方法や目的においては、上記のような違いがある。

分割代入を使用しない場合のコード例

const profile = {
    name: "ちいかわ",
    age: 6,
};

const message = `私の名前は${profile.name}です。年齢は${profile.age}歳です。`

console.log(message); //=> 私の名前はちいかわです。年齢は6歳です。

オブジェクトの分割代入

const profile = {
    name: "ちいかわ",
    age: 6,
};

const { name, age } = profile;

const message = `私の名前は${name}です。年齢は${age}歳です。`
// { }を変数宣言部に使用することでオブジェクトから一致するプロパティを取り出せるようになる。
// 一部のみ取り出したり、順番が違っても問題ない。
// const { age } = profile; 一部取り出し
// const { age, name } = profile  順番が逆

console.log(message);
キーとプロパティは違うもの?

JSのオブジェクトにおいて「キー」と「プロパティ」は密接に関連していますが、微妙に異なる概念である。(これらの用語はしばしば互換的に使われる。)

キー(Key)
オブジェクト内の各値にアクセスするための識別子。
キーは通常、文字列(またはシンボル)で、オブジェクト内で一意でなければならない。

プロパティ(Property)
オブジェクト内のキーとそれに関連付けられた値の組み合わせ。
一般的に、オブジェクトの「プロパティ」とは、そのオブジェクトに属するキーと値のペア全体を指す。

const person = {
  name: "Alice",
  age: 25
};

上記の例では、name と age は、person オブジェクトのキー。
name: "Alice" と age: 25 は、person オブジェクトのプロパティ。
要するに、「キー」はプロパティの名前部分を指し、「プロパティ」とはその名前(キー)と値の組み合わせ全体を指す。
プロパティはオブジェクトの属性や特性を表すために使用され、キーを通じてアクセスされる。

抽出したプロパティに別名をつける

const profile = {
  name: "ちいかわ",
  age: 6,
};

const { name: newName, age: newAge } = profile;
const message = `私の名前は${newName}です。年齢は${newAge}歳です。`

console.log(message); 

配列の分割代入

オブジェクトと同様に分割代入が使用できる。

const profile = ["ちいかわ", 6];

const [name, age] = profile;
// 変数宣言部に[ ]を使用することで、配列に格納された順番に任意の変数名を設定して取り出せる。
// オブジェクトとは違い、順番は入れ替え不可。
// インデックスの途中まで、以降の要素を省略することはできる。ただし、あくまで1番目から順番で、飛ばすことはできない。

const message = `私の名前は${name}です。年齢は${age}歳です。`

console.log(message); 

// オブジェクトと同じく、別名をつけることもできる
const profile = ["ちいかわ", 6];

const [newName, newAge] = profile;
const message = `私の名前は${newName}です。年齢は${newAge}歳です。`

console.log(message); 
haganenoubikhaganenoubik

デフォルト値:=

値が存在しない場合の初期値を設定することで、引数が渡されなかった場合に使用する値を記述できる。
デフォルト値は「引数名の後ろに=で値を記述」 することで設定できる。

デフォルト値を設定していないコード例

const sayHello = (name) => console.log(`こんにちは、${name}さん!`);

sayHello("ハチワレ") //=> こんにちは、ハチワレさん!
sayHello() //=> こんにちは、undifinedさん! 引数を渡していないのでundifinedが設定されている

デフォルト値を設定しているコード例

const sayHello = (name = "モブ" ) => console.log(`こんにちは、${name}さん!`);

sayHello(); //=> こんにちは、モブさん!
sayHello("ハチワレ"); //=> こんにちは、ハチワレさん!
// 引数を渡した場合は、そちらが優先される

オブジェクト分割代入のデフォルト値

配列への分割代入と同様、オブジェクトでデフォルト値を設定した場合も、プロパティが存在する場合はそちらが優先される。

const profile = {
    age: 6,
}

const { name = "モブ" } = profile;

const message = `こんにちは、${name}さん!`

console.log(message); //=> こんにちは、モブさん!
haganenoubikhaganenoubik

スプレッド構文

要素の展開

配列に対して使用することで、内部の要素を順番に展開する。
...(ドット3つ)と記述する。

const pajamaParties = ["mob1", "mob2"];
console.log(pajamaParties); //=> [ 'mob1', 'mob2' ]
console.log(...pajamaParties); //=> mob1 mob2 スプレッド構文を使用

2つの引数を合計して出力する関数での記法を例にした違い

const nums = [10, 20];

const sumFanc = (num1, num2) => console.log(num1 * num2);

// 普通に配列の値を渡す場合
sumFanc(nums[0], nums[1]); //=> 200
// スプレッド記法を使用する場合
sumFanc(...nums); //=> 200

出力結果は同じだが、よりシンプルに記述できることがわかる。

要素をまとめる

const pajamaParties = ["mob1", "mob2", "mob3", "mob4", "mob5"];

const [mob1, mob2, ...mobs] = pajamaParties;

console.log(mob1); //=> mob1
console.log(mob2); //=> mob2
console.log(mobs); //=> [ 'mob3', 'mob4', 'mob5' ] // スプレッド構文によって残りの要素が1つの配列にまとまっている

応用:要素のコピー・結合

const nums1 = [10, 20];
const nums2 = [30, 40];

// スプレッド構文を用いた新たな配列の作成(コピー)
const nums3 = [...nums1];

console.log(nums3); //=> [ 10, 20 ]

// スプレッド構文を用いた2つの配列の結合
const nums4 = [...nums1, ...nums2];

console.log(nums4); //=> [ 10, 20, 30, 40 ]

// スプレッド構文を用いた複数のオブジェクトの結合
const obj1 = {val1: 10, val2: 20};
const obj2 = {val3: 30, val4: 40};

// スプレッド構文を用いた新たなオブジェクトの作成(コピー)
const obj3 = {...obj1};

console.log(obj3);
// スプレッド構文を用いた複数のオブジェクトの結合
const obs = {...obj1, ...obj2};

console.log(obs); //=> { val1: 10, val2: 20, val3: 30, val4: 40 }
// プロパティに重複がある場合は、後のプロパティが優先される。同じ場合は実質的に統合される。
const obs = {...obj1, ...obj2, ...obj3}; //=> { val1: 10, val2: 20, val3: 30, val4: 40 }
haganenoubikhaganenoubik

オブジェクトのショートハンド(省略記法)

省略記法を使わない場合

const name = "ちいかわ";
const age = 6;

// chiikawaオブジェクトを定義(プロパティ名はnameとage)
const chiikawa = {
    name: name,
    age: age,
};

console.log(chiikawa); //=> { name: 'ちいかわ', age: 6 }

省略記法を使った場合

const name = "ちいかわ";
const age = 6;

const chiikawa = {
    name, // 省略記法 
    age, // 省略記法
};

console.log(chiikawa); //=> { name: 'ちいかわ', age: 6 }
console.log(chiikawa.name); //=> ちいかわ
console.log(chiikawa.age); //=> 6
haganenoubikhaganenoubik

map, filter

配列処理での頻出メソッド。

mapメソッドの基本的な役割は、

map関数

const nameList = ["ちいかわ", "ハチワレ", "うさぎ"];

nameList.map((name) => console.log(name));
//=> ちいかわ
//=> ハチワレ
//=> うさぎ

indexを用いたmap関数のコード例
map内の関数は第2引数を引数を置くことができ、その場合はそこに対して0から順番にindex情報が格納される。
👉 「何番目か」という概念が必要な場合は、第2引数を使用できる。

const nameList = ["ちいかわ", "ハチワレ", "うさぎ"];

nameList.map((name, i) => console.log(`${i + 1}番目は${name}です`));
//=> 1番目はちいかわです
//=> 2番目はハチワレです
//=> 3番目はうさぎです

条件を満たさない名前の後ろには「さん」を付与した新たな配列を生成する

const nameList = ["ちいかわ", "くりまんじゅう", "ラッコ"];

const newNameList = nameList.map((name) => {
    //三項演算子を使用
    return name == "ちいかわ" ? name : `${name}さん`; //returnは三項演算子の外に書く
});

console.log(newNameList); //=> [ 'ちいかわ', 'くりまんじゅうさん', 'ラッコさん' ]
console.log(...newNameList); //=> ちいかわ くりまんじゅうさん ラッコさん ※スプレッド構文で配列の要素を順番に展開

filter関数

returnの後に条件式を記述して一致するもののみが返却される関数(フィルタリングする)。

const nameList = ["ちいかわ", "ハチワレ", "うさぎ"];

const newNameList = nameList.filter((name) => {
    return name == "ちいかわ";
});

console.log(newNameList); //=> [ 'ちいかわ' ]
haganenoubikhaganenoubik

capter3:JavaScriptでのDOM操作メモ

JSの関連用語

documentオブジェクト

ブラウザが読み込むWebページのHTMLドキュメント全体を表すオブジェクト。
JSを使ってWebページのDOM(ドキュメントオブジェクトモデル)を操作する際に非常に重要な役割を果たす。
JSを使ってWebページの内容や構造を操作する場合、documentオブジェクトから始める。
DOMツリーの最上位に位置し、Webページのルートを表す。

エントリーポイント

あるプロセスや操作が開始される場所を指す。

Vanilla JS

プレーン(素・ネイティブ)のJavaScriptのこと。
要は、ただのJavaScript。

jQuery

JSのライブラリ。
複雑なJSのメソッドを簡単に扱えるようにするもの。

// 例
document,getElementById("ちいかわ") // Vanila JSの場合
$("#ちいかわ") // jQueryの場合
手続き的

Vanilla JSやjQueryのように「◯◯を〜する」という要領で記述しDOMを操作していく手法を表現する際に使われる。

対して、ReactやVueは宣言的と表現される。

haganenoubikhaganenoubik

React開発の始め方

npx creat-react-app プロジェクト名

cd 作成したプロジェクト

npm start
その他:CodeSandbox

https://codesandbox.io/
Webエディタ上で簡単にJSのプロジェクトが作成でき、コーディングや共有、GitHub連携が行えるサービス。
環境構築不要のため、個人の勉強やコード共有には最適。

Viteを利用したReact環境構築

https://zenn.dev/longbridge/articles/93f63e0423785b

haganenoubikhaganenoubik

JSX(JavaScript XML)記法

import ReactDOM from 'react-dom'; // react-domパッケージからReactDOMをインポートする命令

const App = () => { //Appコンポーネントを定義
    return null; // このコードにおいては、何も表示しない処理を記述
};

ReactDOM.render(<App />, document.getElementById('root')); // ReactDOMのrenderメソッドを呼び出している
// ReactDOM.render(第1引数, 第2引数);
// ReactDOM.render(render対象, render箇所);
第1引数:<App />

Reactでは関数名をHTMLのようにタグで囲むことで コンポーネント として扱うことができる。(JSX記法を用いている)

第2引数:document.getElementById('root')

rootというidを指定している。
root=pubric > index.html内のdivタグ(<div id="root"></div>)

そのため、アプリケーションのルートで「HTMLのここにコンポーネントをレンダリングする」と指定してあげている。

JSX記法では、関数の返却値としてHTMLのタグが記述でき、それをコンポーネントとして扱って画面を構成する。

JSXのルール

👉 コンポーネントのeturn文内で返されるJSX要素は1つのタグで囲われていなければならない。
もしくはReactの Fragment を使用することもできる。
"react"からFragmentをimportする or からのタグで囲む。

import ReactDOM from 'react-dom';
import { Fragment } from 'react'; // Fragmentをimport

const App = () => {
  return (
    <Fragment> // Fragmentで囲む
      <h1>Hello, React</h1>
      <p>Reactの学習中</p>
    </Fragment>
  );
};

ReactDOM.render(<App />, document.getElementById('root'));
import ReactDOM from 'react-dom';

const App = () => {
  return (
    <> // 空のタグで囲む
      <h1>Hello, React</h1>
      <p>Reactの学習中</p>
    </>
  );
};

ReactDOM.render(<App />, document.getElementById('root'));
haganenoubikhaganenoubik

コンポーネントの使い方

なぜコンポーネントを使うのか?

index.jsファイルのみに記述した場合、1つのファイルだけで膨大なコード量になってしまう。
React開発では、画面の要素を様々な粒度のコンポーネントに分割することで、再利用性や保守性を高めるのが基本となっている。

コンポーネントの分割

src配下にApp.jsを新規作成し、index.jsに記述したApp関数を分割する。

// App.js

// index.jsに記述したApp関数をApp.jsに移動し、他のファイルで扱えるようにexportする
export const App = () => {
  return (
    <>
      <h1>Hello, React</h1>
      <p>Reactの学習中</p>
    </>
  );
};
// index.js
import ReactDOM from 'react-dom';
import { App } from './App'; // App.jsでexportしたApp関数をimportする

// App関数は削除する

ReactDOM.render(<App />, document.getElementById('root'));

これでコンポーネント化が完了。

コンポーネントファイルの拡張子

Reactの内部では、JSが動作しているだけなので、.js拡張子で動作させられるが、コンポーネント用の.jsx拡張子も用意されている。
基本的には、コンポーネントファイルには.jsxを使用することを推奨。

haganenoubikhaganenoubik

イベントの扱い方

  • イベントは キャメルケース で記述する。
  • JSXで書いたタグ内で、 { }で囲む ことでJSを記述できる。

イベントの基本的な割り当て方

export const App = () => {
  const onClickButton = () => {
    alert();
  };

  return (
    <>
      <h1>Hello, React</h1>
      <p>Reactの学習中</p>
      <button onClick={onClickButton}>ボタン</button>
    </>
  );
};
haganenoubikhaganenoubik

スタイル(CSS)の扱い方

  • 津城のHTML/CSS同様、各タグにstyle属性を記述することでスタイルを適用できる。
  • 注意点:CSSの各要素は JSのオブジェクト として記述する。
    h1タグの文字を赤に変更
  return (
    <>
      <h1 style={{ color: "red" }}>Hello, React</h1> // 該当のコード
      <p>Reactの学習中</p>
      <button onClick={onClickButton}>ボタン</button>
    </>
  );
スタイルの記法の解説

イベント同様、JSの形式で書くのでstyle={ }となり、その中にオブジェクトでCSSに対応する要素を指定するため、さらに{ }となる。

style={{ color: "red" }}

={ } はJSXで、JSを埋め込むための構文。
CSSの各要素はオブジェクトとして記述する=オブジェクトの記法になるため、 { key: value } の形で記述する。
色指定は文字列として扱われるため""もしくは''で囲む必要がある。

事前に定義したスタイルの適用

 //CSSオブジェクト
  const contentStyle = {
    color: "blue",
    fontSize: "20px" // JSのプロパティ名は「ハイフン」は使えないためキャメルケースで記述
  };

  return (
    <>
      <h1 style={{ color: "red" }}>Hello, React</h1>
      <p style={contentStyle}>Reactの学習中</p> // JSXでのJS埋め込み構文で記述
      <button onClick={onClickButton}>ボタン</button>
    </>
  );
haganenoubikhaganenoubik

Props

Propsとは?

※「property」の短縮形
コンポーネントに渡す引数のようなもの。
Readtコンポーネント間で情報を渡すための仕組み。
親コンポーネントから子コンポーネントにデータを渡すために使われる。
コンポーネントは受け取ったPropsに応じて表示するスタイルや内容を変化させる。

例:ある文字を表示するコンポーネント
通常時:黒文字
エラー時:赤文字
「黒文字用コンポーネント」「赤文字用コンポーネント」のように、各状態に合わせてコンポーネントを用意すると膨大になる。
また、既存のコンポーネントの再利用性も低下する。
👉 動的にコンポーネントを使いまわせるようにPropsで条件を渡す。

Propsがどのように機能しているのか?の自分なりのまとめ

どのようにしてPropsを受け渡しをしているのか?

import/exportによってコンポーネント同士が繋がっている
importの記述がある側:親コンポーネント(=Propsを渡す側)。
exportの記述がある側:子コンポーネント(=Propsを受け取る側)。

// App.jsx
import { ColoredMessage } from "./components/ColoredMessage"; // 子コンポーネントをimportしている

export const App = () => {
  const onClickButton = () => {
    alert();
  };

  return (
    <>
      <h1 style={{ color: "red" }}>Hello, React</h1>
      <ColoredMessage color="blue" message="Reactの学習中ですか?" /> // 子コンポーネントを指定してPropsを渡している
      <ColoredMessage color="pink" message="Reactの学習中です!" /> // 子コンポーネントを指定してPropsを渡している
      <button onClick={onClickButton}>ボタン</button>
    </>
  );
};
// components/ColoredMessage.jsx

export const ColoredMessage = (props) => { // 親コンポーネントにexportしている

  const contentStyle = {
    color: props.color,
    fontSize: "20px"
  };

  return <p style={contentStyle}>{props.message}</p>;
};

特別なProps:children

// children未設定
<ColoredMessage color="pink" message="Reactの学習中です!" />

// <> </>で囲った要素を、childrenとしてProps化
<ColoredMessage color="pink">Reactの学習中です!</ColoredMessage>
// App.jsx ※抜粋
  return (
    <>
      <h1 style={{ color: "red" }}>Hello, React</h1>
      <ColoredMessage color="blue">Reactの学習中ですか?</ColoredMessage>
      <ColoredMessage color="pink">Reactの学習中です!</ColoredMessage>
      <button onClick={onClickButton}>ボタン</button>
    </>
  );

// ColoredMessage.jsx
export const ColoredMessage = (props) => {

  const contentStyle = {
    color: props.color,
    fontSize: "20px"
  };

  return <p style={contentStyle}>{props.children}</p>; // childrenとして使用
};

👉 childerenは、タグで囲んだ要素を丸ごと渡すこともできる。

Propsの応用記法

export const ColoredMessage = (props) => {
  const { color, children } = props; // Propsを分割代入

  const contentStyle = {
    color, // 分割代入によってprops.を省略 + オブジェクトの省略記法でcolorだけの記述でいける
    fontSize: "20px"
  };

  return <p style={contentStyle}>{children}</p>; // 分割代入によってprops.を省略
};

👉 props.~と記述されていることで「Propsが渡されている」と明示されるメリットもあるので、必ずしも省略しなければならないわけではなく、あくまでプロジェクトやルール、好みによる。

haganenoubikhaganenoubik

State(useState)

React開発では、画面に表示するデータや、可変の状態を全てStateとして管理する。
コンポーネントの状態を表す値。

Stateとして扱われる例
  • エラーがあるか
  • モーダルウィンドウが開いているか。
  • ボタンを押せるか。
  • テキストボックスに何を入力したか。

上記のような画面の「状態」をStateとして管理し、イベント実行時等に更新処理を行うことで動的アプリケーションを実現する。

useState

現在主流となっている関数コンポーネントでは、 React Hooks と総称される機能群の中の useState という関数を用いてStateを扱う。
useStateはReactの中に用意されているので、importして使用する。

// useStateをimportする
import { useState } from "react";

//useStateの使用例
const [num, setNum] = useState();
const [State関数, 更新関数]
// useState関数の返却値は、配列の形で[State変数, そのStateを更新するための関数]が設定される

上記の例の場合
num:状態を持った変数
setNum:それを更新する関数
となる。
useStateは関数のため使用する時は()をつけて関数を実行する。

const [num, setNum] = useState(); // numの初期値はundifined
// State変数に初期値を設定したい場合はuseState関数の実行時に引数を指定する
const [num, setNum] = useState(0);
haganenoubikhaganenoubik

再レンダリング・副作用(useEffect)

再レンダリング

再レンダリングって?

簡単に言うと「ReactコンポーネントのUI部分が更新されて画面に再度描画される」こと。
コンポーネントの状態(state)やプロパティ(props)が変更された時に、Reactはそのコンポーネントを再レンダリングして、最新の情報に基づいたUIを表示する。

例:ボタン押下時にカウントアップする

👉 基本認識として State更新時にコンポーネントが再レンダリングされ、関数コンポーネントが再度頭から実行される と覚えておく。

副作用とuseEffect

useEffect:React Hooksの機能群の1つ。コンポーネントの副作用を制御する機能。
使用する際はuseState同様、Reactからimportする。

// useEffectをimportする
import { useEffect } from "react";

// useEffectの宣言
useEffect( 実行する関数, [ 依存する値 ]);

👉 useEffectの役割は ある値が変わった時に限り、ある処理を実行する 機能。

haganenoubikhaganenoubik

2種類のexport

normal export ※便宜上の呼称

// export側
export const SomeComponent = () => {};

// import側
import { SomeComponent } from "./SomeComponet";

default export

default export

export側:export default ~という形で指定する。
import側:
{}
は不要になり、任意の名前をつけてimportできるようになる。

// export側
const SomeComponent = () => {};
export default SomeComponent;

// import側
import SomeComponent from "./SomeComponet";

normal importの場合、importで指定したファイル内に一致する名称のexportがないとエラーが発生する。

// export側:normal export
export const SomeComponent = () => {};

// import側:normal export
import { SomeCom } from "./SomeComponet"; // 不一致のためエラー

default exportの場合、import時に任意の名称をつけることができる。
ただし、1つのファイルで1回しか使えない。
そのファイルの内容を全てまとめてexportするような場面で使用する。

// export側:default export
const SomeComponent = () => {};
export default SomeComponent;

// import側:default export
import { SomeCom } from "./SomeComponet"; // 不一致のためエラー
normal・default、どっちを使うべき?

基本的にはnormal exportを使う。

  • defaultを使用すると、タイポに気付きにくい。
  • 意図しないものをimportする可能性がある。
haganenoubikhaganenoubik

再レンダリングの仕組みと最適化

どんな時に再レンダリングが起きる?