JavaScript基礎(ES6+)
Reactを学ぶ前に、モダンJavaScript(ES6以降)の重要な機能を確認しましょう。これらの知識はReact開発で頻繁に使用します。
アロー関数
アロー関数は、関数を簡潔に記述するための構文です。
基本構文
// 従来の関数
function greet(name) {
return `Hello, ${name}!`
}
// アロー関数
const greet = (name) => {
return `Hello, ${name}!`
}
// 1行で返す場合は中括弧とreturnを省略可能
const greet = (name) => `Hello, ${name}!`
// 引数が1つの場合は括弧も省略可能
const greet = name => `Hello, ${name}!`
複数の引数
const add = (a, b) => a + b
const multiply = (a, b, c) => a * b * c
オブジェクトを返す場合
オブジェクトリテラルを返す場合は、括弧で囲む必要があります。
// NG: 中括弧がブロックと解釈される
const createUser = (name) => { name: name }
// OK: 括弧で囲む
const createUser = (name) => ({ name: name })
// オブジェクトの短縮記法
const createUser = (name) => ({ name })
Reactでの使用例
以下はReactでの使用例です。コンポーネントやPropsの詳細は後の章で学びますが、ここでは「アロー関数がこう使われるんだな」という雰囲気だけ掴んでおけばOKです。
// コンポーネント定義(※コンポーネントは05章、Propsは06章で詳しく説明します)
const Button = ({ label }) => <button>{label}</button>
// イベントハンドラー(※イベント処理は08章で詳しく説明します)
const handleClick = () => {
console.log('クリックされました')
}
// 配列操作(※mapについては後述の「配列のmap・filter・find」で詳しく説明します)
const doubled = numbers.map(n => n * 2)
分割代入
オブジェクトや配列から値を取り出して変数に代入する構文です。
オブジェクトの分割代入
const user = {
name: '田中',
age: 25,
email: 'tanaka@example.com'
}
// 従来の方法
const name = user.name
const age = user.age
// 分割代入
const { name, age, email } = user
console.log(name) // '田中'
console.log(age) // 25
// 別名をつける
const { name: userName, age: userAge } = user
console.log(userName) // '田中'
// デフォルト値
const { name, role = 'guest' } = user
console.log(role) // 'guest'(userにroleがないため)
配列の分割代入
const colors = ['red', 'green', 'blue']
// 従来の方法
const first = colors[0]
const second = colors[1]
// 分割代入
const [first, second, third] = colors
console.log(first) // 'red'
console.log(second) // 'green'
// 特定の要素だけ取り出す
const [, , third] = colors
console.log(third) // 'blue'
// 残りの要素を配列として取得
const [first, ...rest] = colors
console.log(rest) // ['green', 'blue']
関数の引数での分割代入
// オブジェクトを引数として受け取る
const greet = ({ name, age }) => {
return `${name}さん(${age}歳)こんにちは`
}
greet({ name: '田中', age: 25 }) // '田中さん(25歳)こんにちは'
Reactでの使用例
以下はReactでの使用例です。各機能の詳細は後の章で学びますが、ここでは「分割代入がこう使われるんだな」という雰囲気だけ掴んでおけばOKです。
// Propsの分割代入(※Propsは06章で詳しく説明します)
// コンポーネントが受け取る引数(props)から、必要な値を取り出している
const UserCard = ({ name, email, role = 'user' }) => (
<div>
<h2>{name}</h2>
<p>{email}</p>
<span>{role}</span>
</div>
)
// useStateの分割代入(※useStateは07章で詳しく説明します)
// useState(0) は [現在の値, 値を更新する関数] の配列を返す
// ここでは count = 0(初期値)、setCount = 更新関数 として受け取っている
const [count, setCount] = useState(0)
// useReducerの分割代入(※useReducerは14章で詳しく説明します)
const [state, dispatch] = useReducer(reducer, initialState)
スプレッド構文
配列やオブジェクトを展開するための構文です。
配列のスプレッド
const arr1 = [1, 2, 3]
const arr2 = [4, 5, 6]
// 配列の結合
const combined = [...arr1, ...arr2]
console.log(combined) // [1, 2, 3, 4, 5, 6]
// 配列のコピー
const copy = [...arr1]
// 要素の追加
const withNewItem = [...arr1, 4] // [1, 2, 3, 4]
const withFirst = [0, ...arr1] // [0, 1, 2, 3]
オブジェクトのスプレッド
const user = { name: '田中', age: 25 }
// オブジェクトのコピー
const copy = { ...user }
// プロパティの追加・上書き
const updated = { ...user, email: 'tanaka@example.com' }
// { name: '田中', age: 25, email: 'tanaka@example.com' }
const older = { ...user, age: 26 }
// { name: '田中', age: 26 }
// オブジェクトのマージ
const defaults = { theme: 'light', language: 'ja' }
const settings = { theme: 'dark' }
const merged = { ...defaults, ...settings }
// { theme: 'dark', language: 'ja' }
Reactでの使用例
Reactではステートを直接変更してはいけません。必ずスプレッド構文などを使って新しいオブジェクト・配列を作成します。これを「イミュータブル(不変)な更新」と呼びます。
// ❌ NG: 直接変更(Reactが変更を検知できない)
user.name = '鈴木'
setUser(user)
// ✅ OK: 新しいオブジェクトを作成(変更を検知できる)
setUser({ ...user, name: '鈴木' })
なぜ直接変更がダメなのか?
Reactは「オブジェクトの参照が変わったかどうか」で再レンダリングを判断します。直接変更すると参照が同じままなので、画面が更新されません。詳しくは07章で学びます。
// Propsの転送
const Button = (props) => <button {...props} />
// オブジェクトステートの更新(※useStateは07章で詳しく説明します)
const [user, setUser] = useState({ name: '', age: 0 })
setUser({ ...user, name: '田中' })
// 配列ステートの更新
const [items, setItems] = useState([])
setItems([...items, newItem]) // 末尾に追加
setItems([newItem, ...items]) // 先頭に追加
残余引数(Rest Parameters)
関数の引数で残りの引数を配列として受け取る構文です。
// 最初の引数と残りを分ける
const log = (first, ...rest) => {
console.log('First:', first)
console.log('Rest:', rest)
}
log('a', 'b', 'c', 'd')
// First: a
// Rest: ['b', 'c', 'd']
// 配列の分割代入で使用
const [head, ...tail] = [1, 2, 3, 4, 5]
console.log(head) // 1
console.log(tail) // [2, 3, 4, 5]
// オブジェクトの分割代入で使用
const { name, ...otherProps } = { name: '田中', age: 25, email: 'tanaka@example.com' }
console.log(name) // '田中'
console.log(otherProps) // { age: 25, email: 'tanaka@example.com' }
Reactでの使用例
残余引数は、コンポーネントで特定のpropsだけ取り出して、残りをそのまま転送するパターンでよく使います。
// className だけ取り出し、残りのpropsはそのまま button に転送
const Button = ({ className, ...rest }) => (
<button className={`btn ${className}`} {...rest} />
)
// 使用例
<Button className="primary" onClick={handleClick} disabled>
送信
</Button>
// → className は加工して適用
// → onClick, disabled, children はそのまま <button> に転送される
このパターンは、既存のHTML要素やコンポーネントをラップして拡張するときの基本テクニックです。UIコンポーネントライブラリでは頻繁に使われます。
なお、onClick(イベント処理)は08章、children(子要素)は06章で詳しく学びます。ここでは「残りのpropsをまとめて転送できる」ということだけ押さえておけばOKです。
テンプレートリテラル
バッククォートを使った文字列の書き方です。
const name = '田中'
const age = 25
// 従来の方法
const message = name + 'さんは' + age + '歳です'
// テンプレートリテラル
const message = `${name}さんは${age}歳です`
// 複数行の文字列
const html = `
<div>
<h1>${name}</h1>
<p>年齢: ${age}</p>
</div>
`
// 式の埋め込み
const result = `合計: ${1 + 2 + 3}` // '合計: 6'
三項演算子
条件に基づいて値を返す演算子です。
const age = 20
// if-else文
let message
if (age >= 18) {
message = '成人です'
} else {
message = '未成年です'
}
// 三項演算子
const message = age >= 18 ? '成人です' : '未成年です'
// ネスト(読みにくいので注意)
const category = age < 13 ? '子供' : age < 20 ? '10代' : '成人'
Reactでの使用例
// 条件付きレンダリング
const Message = ({ isLoggedIn }) => (
<p>{isLoggedIn ? 'ようこそ!' : 'ログインしてください'}</p>
)
// 使用例
<Message isLoggedIn /> // → 'ようこそ!'
<Message isLoggedIn={false} /> // → 'ログインしてください'
// 条件付きクラス名
const Button = ({ isPrimary }) => (
<button className={isPrimary ? 'btn-primary' : 'btn-secondary'}>
ボタン
</button>
)
// 使用例
<Button isPrimary>送信</Button> // isPrimary = true → 'btn-primary'
<Button>キャンセル</Button> // isPrimary = undefined → 'btn-secondary'
// 条件付き属性
const Input = ({ isDisabled }) => (
<input disabled={isDisabled ? true : undefined} />
)
// 使用例
<Input isDisabled /> // → <input disabled />
<Input /> // → <input />(disabled属性なし)
boolean型propsの正しい渡し方
// ✅ 正しい書き方
<Button isPrimary={true} /> // 明示的にtrue
<Button isPrimary /> // 省略形(これもtrue)
<Button isPrimary={false} /> // 明示的にfalse
<Button /> // 省略(undefinedなのでfalsyとして扱われる)
// ❌ 避けるべき書き方
<Button isPrimary="true" /> // 文字列の "true" が渡される(バグの原因)
isPrimary="true" と書くと、文字列の "true" が渡されます。文字列はtruthyなので動作することもありますが、isPrimary === true の比較で false になるなど、意図しないバグの原因になります。
論理演算子(&&, ||, ??)
AND演算子(&&)
左側がtruthyなら右側を返し、falsyなら左側を返します。
const a = true && 'Hello' // 'Hello'
const b = false && 'Hello' // false
const c = '' && 'Hello' // ''
const d = 0 && 'Hello' // 0
OR演算子(||)
左側がtruthyなら左側を返し、falsyなら右側を返します。
const a = true || 'Default' // true
const b = false || 'Default' // 'Default'
const c = '' || 'Default' // 'Default'
const d = 0 || 'Default' // 'Default'
// デフォルト値の設定
const name = inputName || '名無し'
なぜこのような動きになるのか?(短絡評価)
&& と || は「短絡評価(ショートサーキット)」という仕組みで動作します。
&&(AND)の場合:
- 左側がfalsyなら、右側を評価する必要がない(どちらにせよfalsy)
- → 左側をそのまま返して終了
- 左側がtruthyなら、結果は右側次第
- → 右側を評価して返す
||(OR)の場合:
- 左側がtruthyなら、右側を評価する必要がない(どちらにせよtruthy)
- → 左側をそのまま返して終了
- 左側がfalsyなら、結果は右側次第
- → 右側を評価して返す
この仕組みを利用して、Reactでは条件付きレンダリングやデフォルト値の設定に活用しています。
Null合体演算子(??)
左側がnullまたはundefinedの場合のみ右側を返します。
const a = null ?? 'Default' // 'Default'
const b = undefined ?? 'Default' // 'Default'
const c = '' ?? 'Default' // ''(空文字はnullishではない)
const d = 0 ?? 'Default' // 0(0はnullishではない)
Reactでの使用例
// &&による条件付きレンダリング
const Notification = ({ count }) => (
<div>
{count > 0 && <span className="badge">{count}</span>}
</div>
)
// ||によるフォールバック
// ⚠️ name が空文字 '' でも '名無しさん' になる点に注意
const UserName = ({ name }) => (
<p>{name || '名無しさん'}</p>
)
// ??によるnullish対応
const Counter = ({ initialCount }) => {
// 0も有効な値として扱いたい場合
const count = initialCount ?? 10
return <p>カウント: {count}</p>
}
truthyとfalsy
JavaScriptでは、真偽値以外の値も条件式で評価できます。
falsyな値
以下の値はすべてfalseとして評価されます。
false
0
-0
0n // BigIntの0
'' // 空文字列
null
undefined
NaN
truthyな値
falsy以外のすべての値はtrueとして評価されます。
true
1
'hello' // 空でない文字列
[] // 空配列(注意!)
{} // 空オブジェクト(注意!)
() => {} // 関数
空配列 [] と空オブジェクト {} はtruthyです! これはReact初心者がよくハマるポイントです。「空だからfalsy」と思いがちですが、JavaScriptでは配列とオブジェクトは中身が空でも「存在する」のでtruthyになります。
よくある間違い
// 空配列はtruthyなので注意
const items = []
if (items) {
console.log('配列が存在') // 実行される
}
// 配列が空かどうかは.lengthで確認
if (items.length > 0) {
console.log('要素あり')
}
// または
if (items.length) {
console.log('要素あり')
}
Reactでの使用例
// ❌ よくある間違い: 空配列でも表示されてしまう
const TodoList = ({ todos }) => (
<div>
{todos && <p>{todos.length}件のTodo</p>} {/* todosが[]でも表示される */}
</div>
)
// ✅ 正しい書き方: lengthで確認
const TodoList = ({ todos }) => (
<div>
{todos.length > 0 && <p>{todos.length}件のTodo</p>}
</div>
)
// ✅ 空の場合のメッセージも表示したい場合
const TodoList = ({ todos }) => (
<div>
{todos.length > 0 ? (
<ul>
{todos.map(todo => <li key={todo.id}>{todo.text}</li>)}
</ul>
) : (
<p>Todoはありません</p>
)}
</div>
)
配列のmap・filter・find
map: 各要素を変換
const numbers = [1, 2, 3, 4, 5]
// 各要素を2倍
const doubled = numbers.map(n => n * 2)
// [2, 4, 6, 8, 10]
// オブジェクトの特定プロパティを抽出
const users = [
{ id: 1, name: '田中' },
{ id: 2, name: '鈴木' }
]
const names = users.map(user => user.name)
// ['田中', '鈴木']
filter: 条件に合う要素を抽出
const numbers = [1, 2, 3, 4, 5]
// 偶数だけ抽出
const evens = numbers.filter(n => n % 2 === 0)
// [2, 4]
// オブジェクトのフィルタリング
const users = [
{ name: '田中', active: true },
{ name: '鈴木', active: false },
{ name: '佐藤', active: true }
]
const activeUsers = users.filter(user => user.active)
// [{ name: '田中', active: true }, { name: '佐藤', active: true }]
find: 条件に合う最初の要素を取得
const users = [
{ id: 1, name: '田中' },
{ id: 2, name: '鈴木' },
{ id: 3, name: '佐藤' }
]
const user = users.find(u => u.id === 2)
// { id: 2, name: '鈴木' }
// 見つからない場合はundefined
const notFound = users.find(u => u.id === 99)
// undefined
Reactでの使用例
key propは必須です! Reactがリスト内の各要素を識別するために使います。keyがないと警告が出て、パフォーマンスやバグの原因になります。通常はデータのidを使用します。配列のインデックス(index)は要素の順序が変わる場合に問題を起こすため、推奨されません。
// リストのレンダリング
const UserList = ({ users }) => (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li> {/* key={user.id} が重要 */}
))}
</ul>
)
// フィルタリング + レンダリング
const ActiveUserList = ({ users }) => (
<ul>
{users
.filter(user => user.active)
.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
)
Promise と async/await
非同期処理を扱うための仕組みです。
Promiseの基本
// Promiseを返す関数
const fetchData = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
const success = true
if (success) {
resolve({ data: 'データ' })
} else {
reject(new Error('エラーが発生しました'))
}
}, 1000)
})
}
// thenで結果を受け取る
fetchData()
.then(result => {
console.log(result.data)
})
.catch(error => {
console.error(error.message)
})
async/await
Promiseをより直感的に扱える構文です。
// async関数の定義
const getData = async () => {
try {
const response = await fetch('https://api.example.com/data')
const data = await response.json()
return data
} catch (error) {
console.error('エラー:', error)
throw error
}
}
// 使用例
const main = async () => {
const data = await getData()
console.log(data)
}
複数の非同期処理
// 順次実行: 2つ目の処理が1つ目の結果に依存する場合
const sequential = async () => {
const user = await fetchUser() // 1. まずユーザーを取得
const posts = await fetchPosts(user.id) // 2. そのユーザーのIDで投稿を取得
return { user, posts }
}
// 並列実行: 互いに依存しない処理を同時に実行
const parallel = async () => {
const [users, products] = await Promise.all([
fetchUsers(), // 同時に実行
fetchProducts() // 同時に実行
])
return { users, products }
}
使い分けのポイント
- 順次実行: 後の処理が前の結果を必要とする場合(例: ユーザーID → そのユーザーの投稿)
- 並列実行: 処理同士が独立している場合(例: ユーザー一覧と商品一覧を同時に取得)
並列実行は処理時間を大幅に短縮できます。例えば、各1秒かかる処理を順次実行すると2秒、並列実行なら約1秒で完了します。
Reactでの使用例
以下はReactコンポーネント内でasync/awaitを使う例です。useState(07章)やuseEffect(11章)など未学習の概念が含まれていますが、ここでは「async/awaitがこう使われるんだな」という雰囲気だけ掴んでおけばOKです。
const UserProfile = ({ userId }) => {
// useState(※07章で学習)
const [user, setUser] = useState(null)
const [loading, setLoading] = useState(true)
const [error, setError] = useState(null)
// useEffect(※11章で学習)内でデータ取得
useEffect(() => {
const fetchUser = async () => {
try {
const response = await fetch(`/api/users/${userId}`)
if (!response.ok) throw new Error('取得に失敗しました')
const data = await response.json()
setUser(data)
} catch (err) {
setError(err.message)
} finally {
setLoading(false)
}
}
fetchUser()
}, [userId])
if (loading) return <p>読み込み中...</p>
if (error) return <p>エラー: {error}</p>
return <div>{user.name}</div>
}
ESModules(import/export)
モジュールを分割して管理するための仕組みです。Reactでは、すべてのコンポーネントやユーティリティをモジュールとして管理するため、この構文は必須の知識です。
Reactプロジェクトでの命名規則
- コンポーネントファイル名はPascalCase(例:
Button.tsx,UserProfile.tsx) - ファイル名とコンポーネント名を一致させる
- ユーティリティ関数はcamelCase(例:
utils.ts,formatDate.ts)
名前付きエクスポート
// utils.js
export const add = (a, b) => a + b
export const subtract = (a, b) => a - b
export const PI = 3.14159
// 別の書き方
const multiply = (a, b) => a * b
const divide = (a, b) => a / b
export { multiply, divide }
名前付きインポート
// 特定の関数だけインポート
import { add, subtract } from './utils'
// 別名をつける
import { add as sum } from './utils'
// すべてをまとめてインポート
import * as utils from './utils'
utils.add(1, 2)
デフォルトエクスポート
// Button.tsx
// コンポーネント定義(※05章で詳しく説明します)
const Button = ({ label }) => <button>{label}</button>
export default Button
// 別の書き方
export default function Button({ label }) {
return <button>{label}</button>
}
デフォルトインポート
// 任意の名前でインポートできる
import Button from './Button'
import MyButton from './Button' // 同じものを別名で
混合
// utils.js
export const helper = () => {}
export default function main() {}
// インポート
import main, { helper } from './utils'
名前付きとデフォルトの使い分け
| 特徴 | 名前付きエクスポート | デフォルトエクスポート |
|---|---|---|
| 1ファイルあたりの数 | 複数OK | 1つだけ |
| インポート時の名前 | 固定(変更にはasが必要) | 自由に決められる |
| インポートの構文 | { } が必要 | { } 不要 |
// 名前付き: 名前を合わせる必要あり
import { add, subtract } from './utils'
import { add as sum } from './utils' // 別名にしたい場合は as
// デフォルト: 好きな名前でインポートできる
import Button from './Button'
import MyButton from './Button' // これも同じものを指す
なぜ2種類あるのか?
デフォルトエクスポート = 「このファイルのメインはこれ!」という宣言。
- 1ファイル1コンポーネントのReactに向いている
- ファイル名を見ればわかるので、インポート名は自由でよい
名前付きエクスポート = 「このファイルには複数のものがある」という宣言。
- ユーティリティ関数の集まり、型定義、定数などに向いている
- 名前が固定されるので、チーム内での一貫性が保たれる
Reactでの一般的なパターン
// コンポーネントのエクスポート
// components/Button.tsx
export const Button = ({ label }) => <button>{label}</button>
// または
const Button = ({ label }) => <button>{label}</button>
export default Button
// インデックスファイルでの再エクスポート
// components/index.ts
export { Button } from './Button'
export { Input } from './Input'
export { Card } from './Card'
// 使用側
import { Button, Input, Card } from './components'
named export と default export、どちらを使うべき?
Reactコミュニティでは両方の流派があります:
- named export推奨派: インポート時に名前が固定されるため、検索性が高い
- default export推奨派: ファイルあたり1コンポーネントが明確になる
本書では両方を紹介しますが、チームの規約に従うのがベストです。
オプショナルチェイニング(?.)
ネストしたプロパティに安全にアクセスするための構文です。APIから取得したデータや、オプショナルなPropsを扱うときに、undefinedやnullでエラーになるのを防ぎます。
よくある使用場面
- APIから取得したデータ(レスポンスの形が不確定な場合)
- オプショナルなProps(渡されないかもしれない値)
- ネストしたオブジェクト構造(
user.profile.settings.themeなど)
const user = {
name: '田中',
address: {
city: '東京'
}
}
// 従来の方法
const city = user && user.address && user.address.city
// オプショナルチェイニング
const city = user?.address?.city // '東京'
// プロパティが存在しない場合
const user2 = { name: '鈴木' }
const city2 = user2?.address?.city // undefined(エラーにならない)
// 配列要素へのアクセス
const arr = [1, 2, 3]
const first = arr?.[0] // 1
const tenth = arr?.[9] // undefined
// メソッド呼び出し
const result = obj?.method?.()
従来の && との違い
&& を使った方法は、左側がfalsyなら右側を評価しないという性質を利用しています。オプショナルチェイニングは同じことをより簡潔に書けます。
// 従来: 長くて読みにくい
const city = user && user.address && user.address.city
// オプショナルチェイニング: 簡潔
const city = user?.address?.city
ただし、0 や ''(空文字)を有効な値として扱いたい場合は注意が必要です。&& はこれらをfalsyとして扱いますが、?. は null と undefined のみをスキップします。
Reactでの使用例
const UserProfile = ({ user }) => (
<div>
<p>名前: {user?.name ?? '不明'}</p>
<p>住所: {user?.address?.city ?? '未設定'}</p>
<p>友達: {user?.friends?.[0]?.name ?? 'なし'}</p>
</div>
)
まとめ
この章で学んだES6+の機能は、React開発で頻繁に使用します。
学習のヒント
すべてを暗記する必要はありません。実際にReactを書きながら「あれ、この書き方なんだっけ?」と思ったらこの章に戻ってきてください。使っていくうちに自然と身につきます。
| 機能 | Reactでの主な用途 |
|---|---|
| アロー関数 | コンポーネント定義、イベントハンドラー |
| 分割代入 | Props、useState、useReducer |
| スプレッド構文 | Props転送、ステート更新(イミュータブル) |
| 残余引数 | Propsの転送パターン |
| テンプレートリテラル | 動的な文字列生成 |
| 三項演算子 | 条件付きレンダリング |
| &&, ||, ?? | 条件付きレンダリング、デフォルト値 |
| truthyとfalsy | 条件分岐の理解 |
| map, filter | リストのレンダリング |
| async/await | データフェッチング |
| import/export | モジュール管理 |
| ?.(オプショナルチェイニング) | 安全なプロパティアクセス |
これらの基礎を理解した上で、次の章から実際にReactの開発環境を構築していきましょう。
この章で特に重要なポイント
- スプレッド構文によるイミュータブル更新 - Reactのステート管理で必須
&&による条件付きレンダリング - JSXで頻繁に使用?.と??の組み合わせ - 安全なデータアクセスの定番パターン