Overview
このガイドでは、MERNスタックを使用するReactアプリケーションを作成する方法について説明します。MERNスタックは、MongoDB、Express、React、ノードを使用するWeb開発フレームワークであり、次のレイヤーで構成されています。
データベースレイヤー: MongoDB は、データのストレージと検索を提供します。
アプリケーション階層: Expressとノード.js は、サーバー側ロジックの中間階層を構成します。
プレゼンテーションレイヤー: React は、ユーザー インターフェイスとクライアント側のインタラクションを実装します。
ReactアプリケーションでMongoDBを使用する理由
React アプリケーションデータを MongoDB に保存することで、ドキュメントデータモデルを使用して複雑なクエリ式をビルドできます。document model の柔軟性により、ネストされたデータ構造を保存し、アプリケーションのデザインを迅速に反映できます。MongoDB の水平拡大機能を使用することで、アプリケーションを拡大することもできます。
MongoDBとMERNスタックは、動的に変化するデータ構造を必要とするアプリケーションをサポートします。その結果、このフレームワークは、リアルタイムダッシュボードやコンテンツを継続的に更新する 1 ページのアプリケーションなどの本番環境のアプリケーション向けに適切に設計されています。
クイック スタート チュートリアル
このチュートリアルでは、MERNスタックを使用してWebアプリケーションをビルドする方法を説明します。アプリケーションはサンプルレストランデータにアクセスし、データをクエリし、その結果をローカルでホストされた場に表示します。このチュートリアルには、 MongoDB AtlasでホストされているMongoDBクラスターに接続し、データベースのデータにアクセスして表示する手順も含まれています。
Tip
ReactなしでNode.jsドライバーを使用してMongoDBに接続する場合は、Node.jsドライバーを使い始めるガイドを参照してください。
プロジェクトを設定する
このセクションの手順に従って、プロジェクトの依存関係のインストール、Atlas クラスターの作成、アプリケーションディレクトリの設定を行います。
前提条件を確認します
クイック スタート アプリケーションを作成するには、開発環境に次のソフトウェアがインストールされている必要があります。
前提条件 | ノート |
|---|---|
最新の LTS または 最新リリース バージョンのいずれかをダウンロードする。 | |
コードエディター | このチュートリアルでは Visual Studio Code を使用しますが、お好みのエディターを使用できます。 |
ターミナルアプリとシェル | MacOS ユーザーの場合は、 ターミナル または 類似アプリを使用します。Windowsユーザーの場合は、 PowerShell を使用します。 |
MongoDB Atlasクラスターを作成する
MongoDB Atlas は、MongoDB配置をホストするマネージドクラウドデータベースサービスです。MongoDB配置がない場合は、MongoDBを使い始めるチュートリアルを完了することで、MongoDBクラスターを無料で作成できます(クレジットは不要)。MongoDBを使い始めるチュートリアルでは、このチュートリアルで使用されるsample_restaurantsデータベースなど、サンプルデータセットをクラスターにロードする方法も説明します。
MongoDBクラスターに接続するには、接続 URI を使用する必要があります。接続文字列を検索する方法については、MongoDBを使い始めるチュートリアルの接続文字列の追加セクションを参照してください。
重要
接続stringを安全な場所に保存します。
ファイルを変更しますpackage.json
react-quickstart/serverディレクトリ内の package.jsonファイルに移動します。再利用するためにJavaScriptコードをパッケージ化するための標準形式であるECMAScript モジュールを使用するには、"type"フィールドを指定する既存の行を次の行に置き換えます。
"type": "module",
次のコマンドを実行して、mongodb、express、cors の依存関係をインストールします。
npm install mongodb express cors
このコマンドは、MongoDB、Expressフレームワーク、およびクロスオリジンリソース共有を可能にするcorsノード.jsパッケージをインストールします。
サーバーの構成
プロジェクト構造と依存関係を設定したら、このセクションの手順に従ってサーバーを構成し、MongoDBに接続します。
Expressウェブサーバーの構成
react-quickstart/server ディレクトリから次のコマンドを実行して、server.js という名前のファイルを作成します。
touch server.js
New-Item -ItemType File server.js
次のコードをファイルに貼り付けます。
import express from "express"; import cors from "cors"; import restaurants from "./routes/restaurant.js"; const PORT = process.env.PORT || 5050; const app = express(); app.use(cors()); app.use(express.json()); app.use("/restaurant", restaurants); // start the Express server app.listen(PORT, () => { console.log(`Server listening on port ${PORT}`); });
このファイルは、バックエンドのエントリポイントです。Express サーバーを起動し、React クライアントがサーバーを呼び出せるようにクロスオリジンリソース共有 (CORS) を有効にし、routes/restaurant.js で定義されたルートを /restaurant パスにマウントします。routes/restaurant.js ファイルは後の手順で作成します。
環境変数を設定する
server ディレクトリから次のコマンドを実行して、config.env という名前のファイルを作成します。
touch config.env
New-Item -ItemType File config.env
次の変数をファイルに追加します。
MONGODB_URI=<connection URI> PORT=5050
<connection URI>プレースホルダーを、前の手順で保存した接続 URI に置き換えます。
サーバーをデータベースに接続する
server ディレクトリから次のコマンドを実行して、connection.js ファイルを含む db という名前の新しいフォルダーを作成します。
mkdir db touch db/connection.js
mkdir db New-Item -ItemType File db/connection.js
次のコードをconnection.jsファイルに貼り付けます。
import { MongoClient } from "mongodb"; const uri = process.env.MONGODB_URI || ""; const client = new MongoClient(uri); try { // Connect the client to the server await client.connect(); // Send a ping to confirm a successful connection await client.db("admin").command({ ping: 1 }); console.log( "Pinged your deployment. You successfully connected to MongoDB!" ); } catch(err) { console.error(err); } let db = client.db("sample_restaurants"); export default db;
このファイルはMongoDB配置に接続し、sample_restaurantsデータベースにアクセスして、データベース接続をテストします。データベース接続をdbとしてエクスポートします。次のステップで、routes/restaurant.jsファイルは../db/connection.jsからこのdb接続をインポートしてデータベースをクエリします。
サーバーAPIエンドポイントとなる接続されたデバイスの作成
server ディレクトリから次のコマンドを実行して、restaurant.js ファイルを含む routes という名前の新しいフォルダーを作成します。
mkdir routes touch routes/restaurant.js
mkdir routes New-Item -ItemType File routes/restaurant.js
次のコードをrestaurant.jsファイルに貼り付けます。
import express from "express"; import db from "../db/connection.js"; // Creates an instance of the Express router, used to define our routes const router = express.Router(); // Gets a list of all the restaurants router.get("/", async (req, res) => { let collection = await db.collection("restaurants"); let results = await collection.find({}).toArray(); res.send(results).status(200); }); // Lists restaurants that match the query filter router.get("/browse", async (req, res) => { try { let collection = await db.collection("restaurants"); let query = { borough: "Queens", name: { $regex: "Moon", $options: "i" }, }; let results = await collection.find(query).toArray(); res.send(results).status(200); } catch (err) { console.error(err); res.status(500).send("Error browsing restaurants"); } }); export default router;
このファイルは、db/connection.js から db 接続をインポートし、sample_restaurants データベース内の restaurants コレクションにアクセスし、次の GET エンドポイントとなる接続されたデバイスを定義します。
/:サンプルコレクションからすべてのレストランを検索します/browse: クエリ条件に一致するレストランを検索します。これにより、名前に"Moon"という単語が含まれるクイーンズのレストランがフィルターされます。
クライアントの構成
アプリケーションのサーバーを設定したら、このセクションの手順に従って React を構成し、クライアント コンポーネントを追加します。
Reactテンプレートの追加
react-quickstart ディレクトリに移動します。次に、次のコマンドを実行して、Vite:を使用して React テンプレート ファイルを追加します。
npm create vite@latest client
このコマンドは、一連の設定質問に応答するように要求します。質問ごとに、ドロップダウン メニューから次の応答を選択します。
フレームワーク の選択: React
バリアントの選択: JavaScript
ロールダウンバイト(試験用)を使用するかどうか: いいえ
npmを使用してインストールし、今すぐ起動するかどうか: いいえ
コマンドの実行後、プロジェクトにはクライアント側のスキャフォールディングを含む client ディレクトリが作成されます。
tailwind CSS のインストール
このサンプルアプリケーションでは、 UI形式に tailwind CSSフレームワークを使用します。clientディレクトリに移動し、次のコマンドを実行して tailwind CSS をインストールします。
npm install tailwindcss @tailwindcss/vite
インストール後、vite.config.jsファイルに移動します。強調表示された行に示すように、インポート ステートメントと plugins 配列を更新して @tailwindcss/viteプラグインを追加します。
import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' import tailwindcss from '@tailwindcss/vite' // https://vite.dev/config/ export default defineConfig({ plugins: [ react(), tailwindcss() ], })
次に、client/src/index.cssファイルの内容を次のインポート ステートメントで置き換えます。
@import "tailwindcss";
Reactルーターをセットアップする
client/src/main.jsxファイルに移動し、次のコードを貼り付けます。
import * as React from "react"; import * as ReactDOM from "react-dom/client"; import { createBrowserRouter, RouterProvider } from "react-router-dom"; import App from "./App"; import RestaurantList from "./components/RestaurantList"; import "./index.css"; const router = createBrowserRouter([ { path: "/", element: <App />, children: [ { path: "/", element: <RestaurantList />, }, ], }, { path: "/browse", element: <App />, children: [ { path: "/browse", element: <RestaurantList />, }, ], }, ]); ReactDOM.createRoot(document.getElementById("root")).render( <React.StrictMode> <RouterProvider router={router} /> </React.StrictMode>, );
このファイルは、クライアントのエントリーポイントです。App レイアウト コンポーネントと RestaurantList コンポーネントをインポートし、クライアント側ルーティングを構成し、次のルートを定義します。
/: すべてのレストランを表示するために/restaurant/API エンドポイントとなる接続されたデバイスを呼び出すRestaurantListコンポーネントをレンダーします/browse: フィルターされたレストランを表示するために/restaurant/browseAPI エンドポイントとなる接続されたデバイスを呼び出すRestaurantListコンポーネントをレンダーします
コンポーネントの作成
clientディレクトリから次のコマンドを実行して、2 つのファイルを含む components という名前の新しいフォルダーを作成します。
mkdir src/components cd src/components touch Navbar.jsx RestaurantList.jsx
mkdir src/components cd src/components New-Item -ItemType File Navbar.jsx New-Item -ItemType File RestaurantList.jsx
Navbar.jsxファイルは、必要なコンポーネントにリンクするナビゲーション バーを構成します。次のコードをこのファイルに貼り付けます。
import { NavLink } from "react-router-dom"; export default function Navbar() { return ( <div> <nav className="flex justify-between items-center mb-6"> <NavLink to="/"> <img alt="MongoDB logo" className="h-10 inline" src="https://d3cy9zhslanhfa.cloudfront.net/media/3800C044-6298-4575-A05D5C6B7623EE37/4B45D0EC-3482-4759-82DA37D8EA07D229/webimage-8A27671A-8A53-45DC-89D7BF8537F15A0D.png" ></img> </NavLink> </nav> </div> ); }
RestaurantList.jsxファイルはレストランの表示コンポーネントであり、レストラン情報を検索して表示します。server/routes/restaurant.jsで定義された/restaurant API エンドポイントとなる接続されたデバイスにリクエストを送信します。次のコードをこのファイルに貼り付けます。
import { useEffect, useState } from "react"; import { useLocation } from "react-router-dom"; const Restaurant = (props) => ( <tr className="border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted"> <td className="p-4 align-middle [&:has([role=checkbox])]:pr-0"> {props.restaurant.name} </td> <td className="p-4 align-middle [&:has([role=checkbox])]:pr-0"> {props.restaurant.borough} </td> <td className="p-4 align-middle [&:has([role=checkbox])]:pr-0"> {props.restaurant.cuisine} </td> </tr> ); export default function RestaurantList() { const [restaurants, setRestaurants] = useState([]); const location = useLocation(); // Fetches the restaurants from the database useEffect(() => { async function getRestaurants() { // Determines which endpoint to call based on current route const endpoint = location.pathname === "/browse" ? "http://localhost:5050/restaurant/browse" : "http://localhost:5050/restaurant/"; const response = await fetch(endpoint); if (!response.ok) { const message = `An error occurred: ${response.statusText}`; console.error(message); return; } const restaurants = await response.json(); setRestaurants(restaurants); } getRestaurants(); return; }, [location.pathname]); // Maps each restaurant on the table function restaurantList() { return restaurants.map((restaurant) => { return <Restaurant restaurant={restaurant} key={restaurant._id} />; }); } // Retrieves the dynamic title based on current route const getTitle = () => { return location.pathname === "/browse" ? 'Filtered Restaurants (Queens, containing "Moon")' : "All Restaurants"; }; // Displays the restaurants table return ( <> <h3 className="text-lg font-semibold p-4">{getTitle()}</h3> <div className="border rounded-lg overflow-hidden"> <div className="relative w-full overflow-auto"> <table className="w-full caption-bottom text-sm"> <thead className="[&_tr]:border-b"> <tr className="border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted"> <th className="h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0"> Name </th> <th className="h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0"> Borough </th> <th className="h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0"> Cuisine </th> </tr> </thead> <tbody className="[&_tr:last-child]:border-0"> {restaurantList()} </tbody> </table> </div> </div> </> ); }
最後に、client/src/App.jsxファイルに移動します。このファイルはメインのレイアウト コンポーネントであり、Navbar コンポーネントが子コンポーネントの上にある各ページの上部にレンダーされるようにします。次のコードをこのファイルに貼り付けます。
import { Outlet } from "react-router-dom"; import Navbar from "./components/Navbar"; const App = () => { return ( <div className="w-full p-6"> <Navbar /> <Outlet /> </div> ); }; export default App;
アプリケーションの実行
最後に、このセクションの手順に従ってアプリケーションを実行し、レンダリングされたレストラン データを表示します。
アプリケーション場を開きます
前の手順で検索した http://localhost:5173/ URLを開きます。最初のランディング ページには、sample_restaurants.restaurantsコレクション内のすべてのレストランのリストが表示されます。

次に、 http://localhost:5173/browse URLに移動して、name と boroughフィールドクエリに一致するレストランを表示します。

クイック スタート チュートリアルが完了しました。
これらの手順を完了すると、MongoDB配置に接続し、サンプルレストランデータに対してクエリを実行し、検索した結果をレンダーするReactアプリケーションが作成されます。
トラブルシューティング
このチュートリアルの完了中に問題が発生した場合は、次の一般的な問題と解決策を検討してください。
接続エラー
サーバーターミナルに Pinged your deployment. メッセージではなく接続エラーが表示される場合は、次の点を確認してください。
config.envファイルのMONGODB_URI値は Atlas の接続文字列と一致し、データベースのユーザー名とパスワードが含まれます。sample_restaurantsデータセットをクラスターにロードしました。
CORS Errors
クライアントがデータをリクエストしたときにブラウザ コンソールに CORS エラーが表示される場合は、ルート定義の前に server.jsファイルが app.use(cors()) を呼び出していることを確認してください。
データが表示されない
Web ページが読み込まれてもレストランが表示されない場合は、サーバーとクライアントの両方が別々のターミナル ウィンドウで同時に実行されていることを確認します。React クライアントは http://localhost:5050 でサーバーからデータを取得するため、データを表示するにはサーバーが実行されている必要があります。
ポートの競合
ポート 5050 が既に使用されているためにサーバーが起動できない場合は、config.env ファイルの PORT 値を変更します。サーバーポートを変更する場合は、RestaurantList.jsx 内のエンドポイントとなる接続されたデバイスの URL を一致するように更新します。クライアントポート 5173 が使用されている場合、Vite は次に使用可能なポートを自動的に選択し、ターミナルに URL を出力します。
追加リソース
React、MongoDB、およびMERNスタックの詳細については、次のリソースを表示します。
React のドキュメント
Express ドキュメント
ノード.jsドライバーのドキュメント