1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ツーリングスポットアプリ React化【Part 1】

1
Last updated at Posted at 2026-05-26

環境構築・JSXの書き方・データの移行

このパートで学ぶこと

  • Vite で React プロジェクトを作る
  • JSX で HTML を書く
  • useState で状態を管理する
  • データファイルを React で使えるようにする

ステップ1|Vite で React プロジェクトを作ろう

Vite とは?

React のプロジェクトを素早く作れるツールです。
今まで index.html を直接ブラウザで開いていましたが、
React では 開発サーバーを起動してブラウザで確認 します。

プロジェクトを作成しよう

ターミナルを開き、作業したいフォルダに移動してから以下を実行します。

npm create vite@latest touring-react -- --template react

📌 touring-react がプロジェクト名です。好きな名前に変えても OK です。

次に、作成されたフォルダに移動して必要なパッケージをインストールします。

cd touring-react
npm install

インストールが終わったら、開発サーバーを起動します。

npm run dev

ブラウザで http://localhost:5173 を開くと、Vite のサンプルページが表示されます。

生成されたファイルを確認しよう

touring-react/
├── src/
│   ├── App.jsx       ← メインのコンポーネント(ここを中心に編集する)
│   ├── App.css       ← App.jsx 用のCSS
│   ├── main.jsx      ← React の起動ファイル(基本触らない)
│   └── index.css     ← グローバルなCSS
├── index.html        ← エントリーポイント(基本触らない)
└── package.json      ← プロジェクトの設定ファイル

やってみよう

  • npm run dev でブラウザにサンプルページが表示されることを確認しましょう
  • src/App.jsx を開いて、return(...) の中身を全部消して <h1>ツーリングスポットナビ</h1> だけにしてみましょう
  • 保存すると、ブラウザが自動で更新されることを確認しましょう(これが Hot Reload です)

ステップ2|不要なファイルを整理しよう

最初から入っているサンプルを消そう

Vite で作ると最初からサンプルコードが入っています。
使わないファイルを消して、スッキリした状態から始めましょう。

削除するファイル

  • src/App.css(Vite のサンプル用CSS)
  • src/assets/ フォルダごと

src/index.css の中身を全部消す
(あとでツーリングサイトの style.css の内容をここに貼ります)

src/App.jsx をこの状態にする

function App() {
  return (
    <div>
      <h1>ツーリングスポットナビ</h1>
    </div>
  );
}

export default App;

src/main.jsx を確認する(変更不要)

import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.jsx'

createRoot(document.getElementById('root')).render(
  <StrictMode>
    <App />
  </StrictMode>,
)

📌 main.jsx は「App コンポーネントを index.html#root に表示する」という起動ファイルです。
Vanilla JS での document.getElementById('root') と同じ役割です。

やってみよう

  • 不要なファイルを削除して、ブラウザに「ツーリングスポットナビ」と表示されることを確認しましょう
  • index.css に今の style.css の内容をコピーして、スタイルが当たることを確認しましょう

ステップ3|JSX で HTML を書こう

JSX とは?

React では、JavaScript の中に HTML のような書き方ができます。これを JSX といいます。

// これが JSX
function App() {
  return (
    <div className="main">
      <h1>タイトル</h1>
      <p>テキスト</p>
    </div>
  );
}

HTML と JSX の違いを知ろう

見た目はほぼ同じですが、いくつか違うルールがあります。

classclassName と書く

// HTML
<div class="container">

// JSX
<div className="container">

📌 class は JavaScript の予約語(クラス構文)なので、JSX では className と書きます。

② 全てのタグは閉じる

// HTML(閉じなくてもよい)
<input type="text">
<br>

// JSX(必ず閉じる)
<input type="text" />
<br />

③ return できるのは1つの要素だけ

// NG:2つの要素を並べて返せない
return (
  <h1>タイトル</h1>
  <p>テキスト</p>
);

// OK:1つの要素で包む
return (
  <div>
    <h1>タイトル</h1>
    <p>テキスト</p>
  </div>
);

// OK:<> </> で包む(余分なdivを作りたくない場合)
return (
  <>
    <h1>タイトル</h1>
    <p>テキスト</p>
  </>
);

④ JavaScript の値は {} で埋め込む

const name = '吾妻磐梯スカイライン';

return (
  <p>{name}</p>  // → <p>吾妻磐梯スカイライン</p>
);

やってみよう

  • 今の index.html<header> 部分を JSX に変換して App.jsx に書いてみましょう
  • classclassName に変え忘れがないか確認しましょう

ステップ4|データファイルを React で使えるようにしよう

import / export とは?

Vanilla JS では <script src="./spots.js"> で読み込んでいましたが、
React(Vite)では import / export を使ってファイルを読み込みます。

参考:export の書き方

// src/data/spots.js
export const spots = [
  {
    name: '吾妻磐梯スカイライン',
    lat: 37.71361,
    // ...
  }
];

参考:import の書き方

// App.jsx の一番上に書く
import { spots } from './data/spots';

📌 export const で書いたものは { } で受け取ります(名前付きエクスポート)。
コンポーネントは export default で書くので { } なしで受け取ります。

ファイルを作ろう

src/data/ フォルダを作り、その中に spots.js を作ります。

src/
├── data/
│   └── spots.js   ← 今の spots.js の内容をここに移す
├── App.jsx
└── ...

やってみよう

  • src/data/spots.js を作り、元の spots.js から配列をコピーして export const spots = [...] に書き換えましょう
  • App.jsximport { spots } from './data/spots' と書きましょう
  • console.log(spots)App.jsx に書いて、ブラウザの開発者ツールにデータが出ることを確認しましょう

ステップ5|useState で状態を管理しよう

useState が必要な理由

React では、ただの変数を変えても画面は更新されません

// NG:これでは画面が変わらない
let count = 0;

function App() {
  return (
    <button onClick={() => { count++; }}>
      {count}
    </button>
  );
}

画面に反映させたい値は useState で管理する必要があります。

useState の書き方

import { useState } from 'react';

function App() {
  const [count, setCount] = useState(0); // 初期値は 0

  return (
    <button onClick={() => setCount(count + 1)}>
      {count} 回クリック
    </button>
  );
}
  • count:現在の値(読み取り専用)
  • setCount(新しい値):値を変えて画面を更新する関数
  • useState(0)0 が初期値

📌 setCount(count + 1) を呼ぶと、React が画面を自動で再描画します。
値を変えるときは必ず set〇〇 関数を使う ことがルールです。

絞り込み条件を useState で管理しよう

絞り込みで使う「選択中のエリア」「選択中のタイプ」などを useState で管理します。

参考:複数の状態を持つ書き方

const [selectedArea, setSelectedArea] = useState('');        // 初期値は空文字
const [selectedTypes, setSelectedTypes] = useState([]);      // 複数選択なので配列
const [selectedSeasons, setSelectedSeasons] = useState([]);
const [selectedLevels, setSelectedLevels] = useState([]);

参考:セレクトボックスの値を useState と連動させる

<select
  value={selectedArea}
  onChange={e => setSelectedArea(e.target.value)}
>
  <option value="">選択してください</option>
  <option value="hokkaido">北海道</option>
  {/* ... */}
</select>

📌 value={selectedArea} で「今の状態を表示」、
onChange で「変えたとき状態を更新」する、この組み合わせが React のフォームの基本です。

参考:ボタンのトグル(active クラスの切り替え)

// 配列に含まれていれば active、なければ非 active
<button
  className={selectedTypes.includes('') ? 'select-button active' : 'select-button'}
  onClick={() => {
    if (selectedTypes.includes('')) {
      setSelectedTypes(selectedTypes.filter(t => t !== ''));
    } else {
      setSelectedTypes([...selectedTypes, '']);
    }
  }}
></button>

やってみよう

  • selectedAreaselectedTypesselectedSeasonsselectedLevels の4つを useState で宣言しましょう
  • セレクトボックスに valueonChange を設定して、選択した値が変わることを console.log で確認しましょう
  • ボタンを押したとき selectedTypes に値が追加・削除されることを確認しましょう

ステップ6|絞り込みロジックを移そう

filterSpots 関数はそのまま使える

今の script.js にある filterSpots 関数は純粋な JavaScript なので、ほぼそのまま使えます。
src/utils/filterSpots.js というファイルに切り出して、export しましょう。

参考:ユーティリティ関数の切り出し

// src/utils/filterSpots.js
export function filterSpots(spots, area, types, seasons, levels) {
  return spots.filter(spot => {

    if (area && spot.area !== area) return false;

    if (types.length > 0 &&
      !(Array.isArray(spot.type)
        ? spot.type.some(t => types.includes(t))
        : types.includes(spot.type))) return false;

    // seasons、levels も同様に書く

    return true;
  });
}

絞り込み結果も useState で持とう

絞り込んだあとのスポット一覧を useState で管理します。
初期値は「全件」にしておきます。

参考:絞り込み結果の状態

const [filteredSpots, setFilteredSpots] = useState(spots);

参考:検索ボタンを押したとき

<button onClick={() => {
  const result = filterSpots(spots, selectedArea, selectedTypes, selectedSeasons, selectedLevels);
  setFilteredSpots(result);
}}>
  検索する
</button>

参考:リセットボタンを押したとき

<button onClick={() => {
  setSelectedArea('');
  setSelectedTypes([]);
  setSelectedSeasons([]);
  setSelectedLevels([]);
  setFilteredSpots(spots); // 全件に戻す
}}>
  リセット
</button>

やってみよう

  • src/utils/filterSpots.js を作り、元の関数を移しましょう
  • filteredSpots の状態を作り、検索ボタンで絞り込み結果が変わることを console.log で確認しましょう
  • リセットボタンで全件に戻ることを確認しましょう

Part 1 まとめ

このパートで作ったものを整理します。

src/
├── data/
│   └── spots.js          ← スポットデータ(export あり)
├── utils/
│   └── filterSpots.js    ← 絞り込み関数(export あり)
├── App.jsx               ← useState でエリア・タイプ・季節・難易度・絞り込み結果を管理
├── main.jsx
└── index.css             ← style.css の内容をコピー

学んだこと

  • Vite で React プロジェクトを作る方法
  • JSX の書き方(className、閉じタグ、{}
  • import / export でファイルをつなぐ方法
  • useState で状態を管理して画面を更新する方法

→ Part 2 では、コンポーネント分割・Google マップ表示に進みます

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?