React・Reactを知る

Reactの前に、JavaScriptの書き方を確認する

Reactのコードが読めない原因は、Reactではなく最近のJavaScriptの書き方にあることが多いです。アロー関数・分割代入・スプレッド構文・mapなど、Reactの記事に必ず出てくる書き方だけを、前後を書き比べながら一気に確認します。

Reactのコードが読めないとき、つまずいているのはReactではなくJavaScriptの書き方だった——というのはとてもよくあります。

const BirdCard = ({ name, area }) => (
  <div className="card">
    <h2>{name}</h2>
    {area && <span>{area}</span>}
  </div>
)

この5行に、Reactの機能はほとんど出てきません。矢印・波かっこ・&&——全部JavaScriptの書き方です。この回で、そこだけをまとめて片づけます。

アロー関数——関数を短く書く

いちばんよく出てくる書き方です。

// これまでの書き方
function add(a, b) {
  return a + b
}

// アロー関数
const add = (a, b) => {
  return a + b
}

// 中身が「返すだけ」なら、returnと波かっこを省略できる
const add = (a, b) => a + b

3つめの形がReactでは頻出します。returnが消えているだけで、やっていることは同じです。

引数が1つのときは、かっこも省略できます。

const double = (n) => n * 2
const double = n => n * 2 // これも同じ(どちらの書き方も見かけます)

Reactではこんな形で出てきます。

<button onClick={() => setCount(count + 1)}>ふやす</button>

() => setCount(count + 1)は、引数なしで、押されたらsetCount(...)を実行する関数です。ここで「実行される関数そのもの」を渡しているのがポイントで、onClick={setCount(count + 1)}と書くとその場で実行されてしまいます(よくある間違いなので、後の回でもう一度出てきます)。

分割代入——中身を取り出して名前を付ける

オブジェクトから値を取り出すとき、名前をそのまま変数にできます。

const bird = { name: 'シマエナガ', area: '北海道', rare: 3 }

// これまでの書き方
const name = bird.name
const area = bird.area

// 分割代入
const { name, area } = bird

左側の波かっこは「オブジェクトを作る」のではなく「取り出す」の合図です。ここが最初は読みにくいところです。

配列でも同じことができます。こちらは名前ではなく順番で取り出します。

const [first, second] = ['シマエナガ', 'スズメ']
// first → 'シマエナガ'  second → 'スズメ'

この形はReactのuseStateでそのまま出てきます。

const [count, setCount] = useState(0)

useStateが返す配列の1番目をcount、2番目をsetCountという名前で受け取っている——それだけの話です。countsetCountという名前は自分で決めています。

関数の引数でも分割代入は使えます。Reactのコンポーネントはほぼこの形です。

// propsというオブジェクトを受け取って中身を使う
function BirdCard(props) {
  return props.name
}

// 受け取るところで分割代入する(Reactの記事はほぼこちら)
function BirdCard({ name }) {
  return name
}

スプレッド構文——中身を広げてコピーする

...は、配列やオブジェクトの中身を1つずつ取り出して並べ直す書き方です。

const birds = ['シマエナガ', 'スズメ']

const added = [...birds, 'フクロウ']
// → ['シマエナガ', 'スズメ', 'フクロウ'](元のbirdsはそのまま)

オブジェクトでも同じです。

const bird = { name: 'シマエナガ', rare: 3 }
const updated = { ...bird, rare: 5 }
// → { name: 'シマエナガ', rare: 5 }(rareだけ上書き)

なぜこんな回りくどいことをするのか。Reactでは、いま持っているデータを直接書きかえてはいけないからです。

// ✕ Reactでは画面が更新されない
birds.push('フクロウ')

// ○ 新しい配列を作って渡す
setBirds([...birds, 'フクロウ'])

Reactは「前のデータと新しいデータが別物かどうか」で画面を作り直すかを判断します。push元の配列そのものを書きかえるので、Reactから見ると「何も変わっていない」ように見えてしまうのです。

mapとfilter——配列から配列を作る

map1つ1つを別のものに変換した新しい配列を返します。

const names = ['シマエナガ', 'スズメ']
const items = names.map((name) => `🐦 ${name}`)
// → ['🐦 シマエナガ', '🐦 スズメ']

filter条件に合うものだけを残した新しい配列を返します。

const rare = birds.filter((bird) => bird.rare >= 3)

Reactでは、mapそのまま画面の一覧になります

<ul>
  {birds.map((bird) => (
    <li key={bird.id}>{bird.name}</li>
  ))}
</ul>

配列の中身が「文字列」から「<li>」に変わっただけで、mapのやっていることは同じです。一覧を作る回で必ず出てくるので、ここだけは手で書いて慣れておくと効きます。

JavaScript配列:たくさんの値をまとめる配列そのものがあやしい人はこちらへ。map・filterの土台になります

三項演算子と&&——条件を式で書く

Reactではifが使えない場所(JSXの中)があるので、式で書ける条件分岐をよく使います。

// 三項演算子: 条件 ? 真のとき : 偽のとき
const label = isFavorite ? '★' : '☆'

// && : 左が真のときだけ右を返す
const badge = rare >= 3 && 'レア'

JSXの中ではこうなります。

{isFavorite ? '★' : '☆'}
{rare >= 3 && <span className="badge">レア</span>}

&&って、こんな使い方していいの?」と感じたら正しい感覚です。本来は条件式のための記号を、表示の出し分けに流用している書き方で、Reactの世界では完全に定番になっています。

テンプレートリテラル——文字列に値を混ぜる

バッククォート(`)で囲むと、${}の中に値を書けます。

const name = 'シマエナガ'
const message = `${name}をお気に入りにしました`

Tailwindのクラスを組み立てるときにも使いますが、Tailwindでは注意が必要です。

Tailwind CSSクラス名の読み方Tailwindのクラス名の規則はこちら。Reactの中でも規則は同じです

importとexport——ファイルを分ける

Reactでは1ファイル=1コンポーネントが基本なので、ファイルをまたいで受け渡しをします。

// BirdCard.jsx(渡す側)
function BirdCard() { /* … */ }
export default BirdCard
// App.jsx(受け取る側)
import BirdCard from './components/BirdCard.jsx'

export default1ファイルに1つだけ置ける「主役」の書き出し方です。受け取る側は名前を自由に決められます(import Card from …でも動きます)。

主役以外も出したいときは、名前つきで書き出します。

// data/birds.js
export const birds = [ /* … */ ]
// 受け取る側は名前をそろえる(波かっこが要る)
import { birds } from './data/birds.js'

波かっこの有無で書き方が変わるのがまぎらわしいところです。「defaultは波かっこなし、名前つきは波かっこあり」と覚えてください。

書き出し方受け取り方1ファイルに
export default BirdCardimport BirdCard from '…'1つだけ
export const birds = …import { birds } from '…'いくつでも

変数はconstから

最後に短く。まずconstで書き、書きかえが必要になったときだけletにします。Reactでは状態の書きかえをuseStateが受け持つので、letはほとんど出てきません。

const birds = []       // 中身の追加はできる(再代入だけができない)
let count = 0          // 数えるための一時変数などに

公式ドキュメントも見てみる

Reactの公式にも、この回と同じ趣旨のまとめページがあります。より深く知りたくなったときの行き先として覚えておいてください。

ja.react.dev外部サイトJSX に波括弧で JavaScript を含める – ReactJSXの中で波かっこを使って値を書く話。この回で扱った書き方が、Reactのどこで効いてくるかが分かります

このレッスンのまとめ

  1. アロー関数——(a, b) => a + breturnを省略した関数。Reactではこの形が既定
  2. 分割代入——const { name } = birdは取り出し。useState[count, setCount]も同じ書き方
  3. スプレッド構文——[...birds, 新しい鳥]元をこわさずコピー。Reactの状態更新はこれが必須
  4. mapは配列から配列を作る。Reactではそのまま一覧の描画になる
  5. 三項演算子と&&は、JSXの中で条件を書くための道具
  6. export defaultは波かっこなし、名前つきは波かっこありで受け取る

準備は終わりです。次からは実際に手を動かします。ViteとTailwindで、Reactが動く環境を10分で作ります。

よくある質問

アロー関数とふつうの関数はどう違いますか?
書く量が短いのが見た目の違いです。Reactの学習範囲では「短い書き方」と思って差し支えありません。中身の違い(thisの扱い)は、クラスを使わない今の書き方ではほとんど問題になりません。
分割代入は必ず使わないといけませんか?
いいえ。props.nameのように毎回書いても同じ動きです。ただしReactの記事やライブラリのドキュメントは分割代入で書かれているので、読めるようにはしておく必要があります。
スプレッド構文(...)は何をしているのですか?
配列やオブジェクトの中身を1つずつ取り出して並べ直します。結果として「元をこわさずにコピーを作る」ことができます。Reactでは状態を書きかえるときに元の配列を直接いじってはいけないので、この書き方が毎回出てきます。
mapとforEachはどちらを使えばいいですか?
新しい配列がほしいときはmap、ほしくないときはforEachです。Reactでは配列から画面の要素を作るのでmapを使います。forEachは何も返さないので、画面には何も出ません。