概要: このチュートリアルでは、Webブラウザが提供する組み込みのFetch APIを使用して、ReactアプリでAPIを呼び出す方法を学習します。
Wikipedia検索Reactアプリの紹介
Wikipediaの記事を検索できる新しいReactアプリを作成します。そのためには、ReactアプリはWikipedia Search APIを呼び出す必要があります。

Reactアプリは次のようになります。

このReactアプリは、次のコンポーネントに分割できます。

コンポーネントの階層は次のとおりです。
このコンポーネント階層では、
App
コンポーネントは、他のコンポーネントを含む親コンポーネントです。SearchBar
コンポーネントでは、検索語を入力してEnterキーを押して送信できます。ArticleList
コンポーネントは、記事のリストを含む検索結果のレンダリングを担当します。Article
コンポーネントは、検索結果の各記事をレンダリングします。
PropsとStateのデザイン
アプリを作成する前に、いくつか回答が必要な質問があります。
- アプリケーションの状態とは何ですか?
- どのコンポーネントがAPI呼び出しを処理する必要がありますか?
- propsシステムをどのように設計する必要がありますか?
アプリは記事のリストを表示するため、状態変数として記事の配列を持つ必要があります。
const [articles, setArticles] = useState([]);
Code language: JavaScript (javascript)
App
コンポーネントはArticleList
コンポーネントを使用して記事リストをレンダリングするため、articles
配列をpropとしてArticleList
に渡す必要があります。
さらに、ArticleList
は各article
をpropとしてArticle
コンポーネントに渡し、各記事をレンダリングする必要があります。
SearchBar
コンポーネントでWikipedia APIを呼び出すと、記事のリストを取得できます。しかし、どのようにSearchBar
コンポーネントからApp
コンポーネントに記事リストを渡すのでしょうか?
通常、Reactでは、親コンポーネントから子コンポーネントにpropsを渡すことができますが、子コンポーネントから親コンポーネント、または兄弟コンポーネント間では渡すことができません。
この制限を克服するために、App
コンポーネントからSearchBar
コンポーネントにコールバック関数をpropとして渡すことができます。
ユーザーが検索フォームを送信すると、コールバック関数onSearch
を呼び出して、App
コンポーネントのarticles
状態を更新できます。

新しいReactアプリを作成する
まず、コンピューターでターミナルを開き、create-react-app
コマンドを使用して新しいReactアプリを作成します。
npx create-react-app wiki-search
Code language: JavaScript (javascript)
次に、src
ディレクトリ内のすべてのファイルを削除します。
次に、src
ディレクトリに新しいindex.js
ファイルを作成し、次のコードを追加します。
import ReactDOM from 'react-dom/client';
import App from './App.js';
const el = document.querySelector('#root');
const root = ReactDOM.createRoot(el);
root.render(<App />);
Code language: JavaScript (javascript)
index.js
ファイルは、画面にApp
コンポーネントをレンダリングします。
その後、src
ディレクトリにApp.js
という名前の新しいファイルを作成し、次のコードを追加します。
const App = () => {
return <div>Wikipedia Search</div>;
};
export default App;
Code language: JavaScript (javascript)
最後に、ターミナルで次のコマンドを実行してReactアプリを実行します。
npm start
Code language: JavaScript (javascript)
Webブラウザのhttp://localhost:3000
に新しいReactアプリが表示されます。
APIの呼び出し
ReactアプリからAPIを呼び出す方法はいくつかあります。最も簡単な方法は、Webブラウザが提供するネイティブのFetch APIを使用することです。サードパーティのパッケージをインストールする必要がないためです。
まず、APIエンドポイントを渡してfetch()
メソッドを呼び出します。
const response = await fetch(url);
Code language: JavaScript (javascript)
次に、Response
オブジェクトのjson()
メソッドを呼び出して、JSON本文の内容を解析します。
const results = await response.json();
Code language: JavaScript (javascript)
3番目に、解析されたJSONデータを返します。
return results;
Code language: JavaScript (javascript)
Wikipedia Search APIの呼び出し
まず、src
ディレクトリにapi.js
という名前の新しいファイルを作成します。
次に、指定された検索語に対してWikipedia Search APIを呼び出し、記事の配列を返すsearch()
関数を定義します。
export const search = async (searchTerm) => {
const url = `https://en.wikipedia.org/w/api.php?action=query&list=search&prop=info|extracts&inprop=url&utf8=&format=json&origin=*&srsearch=${searchTerm}`;
const response = await fetch(url);
const results = await response.json();
return results.query.search;
};
Code language: JavaScript (javascript)
仕組み
ステップ1. 検索語を受け入れる検索関数を定義します。
export const search = async (searchTerm) => {
// ...
}
Code language: JavaScript (javascript)
ステップ2. API URLと検索語を連結してAPIエンドポイントを構築します。
const url = `https://en.wikipedia.org/w/api.php?action=query&list=search&prop=info|extracts&inprop=url&utf8=&format=json&origin=*&srlimit=10&srsearch=${searchTerm}`;
Code language: JavaScript (javascript)
ステップ3. APIからJSONデータを返します。
const response = await fetch(url);
const results = await response.json();
return results.query.search;
Code language: JavaScript (javascript)
検索結果には、pageid
、title
、およびsnippet
が含まれます。 title
とsnippet
にはHTMLタグが含まれている場合があります。
HTMLタグを取り除くために、src
ディレクトリに新しいファイルutil.js
を作成し、stripHTML()
関数を次のように定義できます。
export const stripHtml = (html) => {
let div = document.createElement('div');
div.innerHTML = html;
return div.textContent;
};
Code language: JavaScript (javascript)
Article
コンポーネントでstripHTML
を使用して、title
とsnippet
からHTMLを取り除きます。
Reactコンポーネントの作成
Reactアプリのコンポーネントを作成します。
Appコンポーネント
次のApp
コンポーネントには、SearchBar
とArticleList
コンポーネントが含まれています。
import { useState } from 'react';
import { search } from './api';
import SearchBar from './components/SearchBar';
import ArticleList from './components/ArticleList';
import './App.css';
import logo from './wikipedia-logo.png';
const App = () => {
const [articles, setArticles] = useState([]);
const handleSearch = async (searchTerm) => {
const results = await search(searchTerm);
setArticles(results);
};
return (
<>
<header>
<img src={logo} alt="wikipedia" />
<h1>Wikipedia Search</h1>
<SearchBar onSearch={handleSearch} />
</header>
<main id="searchResult">
<ArticleList articles={articles} />
</main>
</>
);
};
export default App;
Code language: JavaScript (javascript)
仕組み
ステップ1. App
はある程度の状態を保持するため、reactライブラリからuseState
関数をインポートします。
import { useState } from 'react';
Code language: JavaScript (javascript)
ステップ2. api.js
モジュールからsearch
関数をインポートします。
import { search } from './api';
Code language: JavaScript (javascript)
ステップ3. SearchBar
とArticleList
コンポーネントをインポートします。
import SearchBar from './components/SearchBar';
import ArticleList from './components/ArticleList';
Code language: JavaScript (javascript)
ステップ4. App.cssとwikipedia-logo.png
ファイルをインポートします。
import './App.css';
import logo from './wikipedia-logo.png';
Code language: JavaScript (javascript)
ステップ5. App
コンポーネントを定義します。
const App = () => {
// ...
};
Code language: JavaScript (javascript)
ステップ5. 記事の配列である状態(articles
)を定義し、そのデフォルト値を空の配列に初期化します。
const [articles, setArticles] = useState([]);
Code language: JavaScript (javascript)
ステップ6. search
関数を呼び出して検索結果を取得し、これらの結果でarticles
状態を更新するhandleSearch()
関数を定義します。
const handleSearch = async (searchTerm) => {
const results = await search(searchTerm);
setArticles(results);
};
Code language: JavaScript (javascript)
ステップ7. ロゴ、見出し、SearchBarコンポーネント、およびArticleListコンポーネントを含むJSXを返します。
return (
<>
<header>
<img src={logo} alt="wikipedia" />
<h1>Wikipedia Search</h1>
<SearchBar onSearch={handleSearch} />
</header>
<main id="searchResult">
<ArticleList articles={articles} />
</main>
</>
);
Code language: JavaScript (javascript)
JSXでは、
- handleSearch関数をSearchBarコンポーネントのonSearch propに渡します。
- articles状態をpropとしてArticleListコンポーネントに渡します。
読み込み状態の表示
APIを呼び出すと、結果が返されるまでに時間がかかるため、読み込みインディケーターを表示することは、ユーザーエクスペリエンスの向上に重要です。
そのため、App
コンポーネントに新しい状態変数isLoading
を追加します。
const [isLoading, setIsLoading] = useState(false);
Code language: JavaScript (javascript)
search関数を呼び出す前に、isLoading
の値をtrue
に設定し、結果を取得した後にその値をfalse
に設定します。
const handleSearch = async (searchTerm) => {
setIsLoading(true);
const results = await search(searchTerm);
setArticles(results);
setIsLoading(false);
};
Code language: JavaScript (javascript)
読み込みインディケーターを表示するには、次のように条件付きレンダリングを使用します。
{isLoading && <p>Loading...</p>}
Code language: HTML, XML (xml)
エラー処理
APIを呼び出すと、ネットワークの切断やサーバーの停止など、さまざまなエラーが発生する可能性があります。そのため、問題が発生した場合にユーザーにエラーメッセージを表示することが重要です。
これを処理するために、Appコンポーネントに新しい状態変数を追加し、エラーが発生するたびに更新できます。
const [error, setError] = useState(null);
Code language: JavaScript (javascript)
エラーを処理するために、try…catchステートメントを使用できます。エラーが発生した場合、エラー状態変数を更新できます。
const handleSearch = async (searchTerm) => {
setIsLoading(true);
try {
const results = await search(searchTerm);
setArticles(results);
} catch (err) {
setError('Something went wrong. Please try again.');
} finally {
setIsLoading(false);
}
};
Code language: JavaScript (javascript)
このコードでは、catch
ブロックでエラー状態変数をエラーメッセージに設定します。エラーメッセージをレンダリングするには、条件付きレンダリングを使用できます。
{error && <p className="error">{error}</p>}
Code language: HTML, XML (xml)
App.js
コンポーネントの完全なコードは次のとおりです。
import { useState } from 'react';
import SearchBar from './components/SearchBar';
import ArticleList from './components/ArticleList';
import { search } from './api';
import './App.css';
import logo from './wikipedia-logo.png';
const App = () => {
const [articles, setArticles] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
const handleSearch = async (searchTerm) => {
setIsLoading(true);
try {
const results = await search(searchTerm);
setArticles(results);
} catch (err) {
setError('Something went wrong. Please try again.');
} finally {
setIsLoading(false);
}
};
return (
<>
<header>
<img src={logo} alt="wikipedia" />
<h1>Wikipedia Search</h1>
<SearchBar onSearch={handleSearch} />
</header>
<main id="searchResult">
{isLoading && <p>Loading...</p>}
{error && <p className="error">{error}</p>}
<ArticleList articles={articles} />
</main>
</>
);
};
export default App;
Code language: JavaScript (javascript)
ユーザーが新しい検索リクエストを開始した場合に以前の検索リクエストを中止するために、AbortControllerの組み込みを検討することをお勧めします。
SearchBarコンポーネント
SearchBar
コンポーネントでは、ユーザーが検索語を入力し、検索のためにAPIを呼び出す関数を実行できます。
import { useState } from 'react';
const SearchBar = () => {
const [searchTerm, setSearchTerm] = useState('');
const handleSubmit = (event) => {
event.preventDefault();
onSearch(searchTerm);
};
return (
<form onSubmit={handleSubmit}>
<input
type="search"
name="searchTerm"
id="searchTerm"
placeholder="Enter a search term..."
value={searchTerm}
onChange={(event) => {
setSearchTerm(event.target.value);
}}
/>
</form>
);
};
export default SearchBar;
Code language: JavaScript (javascript)
仕組み
ステップ1. reactライブラリからuseState
関数をインポートします。
import { useState } from 'react';
Code language: JavaScript (javascript)
ステップ2. 関数onSearch
をpropとして受け入れるSearchBar
コンポーネントを定義します。
const SearchBar = ({ onSearch }) => {
// ..
}
Code language: JavaScript (javascript)
ステップ3. SearchBar
コンポーネントのsearchTerm
状態を定義し、そのデフォルト値を空の文字列に初期化します。
const [searchTerm, setSearchTerm] = useState('');
Code language: JavaScript (javascript)
ステップ4. 送信イベントを処理するイベントハンドラーを作成します。
const handleSubmit = (e) => {
e.preventDefault();
onSearch(searchTerm);
};
Code language: JavaScript (javascript)
送信イベントでは、e.preventDefault()
を呼び出して、ユーザーがフォームを送信したときにページ全体がリロードされないようにし、引数としてsearchTerm
状態を使用してonSearch
関数を呼び出します。
ステップ5. フォームと入力要素を含むJSXを返します。
return (
<form onSubmit={handleSubmit}>
<input
type="search"
name="searchTerm"
id="searchTerm"
placeholder="Enter a search term..."
value={searchTerm}
onChange={(e) => {
setSearchTerm(e.target.value);
}}
/>
</form>
);
Code language: JavaScript (javascript)
JSX
では、
handleSubmit
イベントハンドラーをフォームのonSubmit
propに接続します。- 入力要素の変更イベントハンドラーで
setSearchTerm
を呼び出して状態を更新します。e.target
.valueは、入力要素の現在の値を返します。setSearchTerm
関数は、新しい入力値をコンポーネントのsearchTerm
状態に代入します。
ステップ6. デフォルトエクスポートを使用してSearchBar
コンポーネントをエクスポートします。
export default SearchBar;
Code language: JavaScript (javascript)
ArticleListコンポーネント
ArticleList
コンポーネントは、Article
コンポーネントのリストを表示します。
import Article from './Article';
const ArticleList = ({ articles }) => {
const renderedArticles = articles.map((article) => {
return <Article key={article.pageid} article={article} />;
});
return <div>{renderedArticles}</div>;
};
export default ArticleList;
Code language: JavaScript (javascript)
仕組み
ステップ1. Articleコンポーネントをインポートします。
import Article from './Article';
Code language: JavaScript (javascript)
ステップ2. 記事の配列をpropとして受け取り、Articleコンポーネントを使用して各記事をレンダリングするArticleList
コンポーネントを定義します。
const ArticleList = ({ articles }) => {
const renderedArticles = articles.map((article) => {
return <Article key={article.pageid} article={article} />;
});
return <div>{renderedArticles}</div>;
};
Code language: JavaScript (javascript)
ステップ3. ArticleList
コンポーネントをデフォルトコンポーネントとしてエクスポートします。
export default ArticleList;
Code language: JavaScript (javascript)
Articleコンポーネント
Article
コンポーネントは記事をレンダリングします。
import { stripHtml } from '../util';
const Article = ({ article }) => {
const url = `https://en.wikipedia.org/?curid=${article.pageid}`;
const title = stripHtml(article.title);
const snippet = stripHtml(article.snippet);
return (
<article>
<a href={url} title={title}>
<h2>{title}</h2>
</a>
<div className="summary">{snippet}...</div>
</article>
);
};
export default Article;
Code language: JavaScript (javascript)
仕組み
ステップ1. util
ライブラリからstripHTML
関数をインポートします。
import { stripHtml } from '../util';
Code language: JavaScript (javascript)
ステップ2. article
propをレンダリングするArticle
コンポーネントを作成します。
const Article = ({ article }) => {
const url = `https://en.wikipedia.org/?curid=${article.pageid}`;
const title = stripHtml(article.title);
const snippet = stripHtml(article.snippet);
return (
<article>
<a href={url} title={title}>
<h2>{title}</h2>
</a>
<div className="summary">{snippet}...</div>
</article>
);
};
Code language: JavaScript (javascript)
Article
コンポーネントでは、
- Wikipediaの記事へのURLを構築します。
- articleオブジェクトのタイトルとスニペットからHTMLタグを取り除きます。
<article>
JSX要素を返します。
ステップ3. Article
コンポーネントをデフォルトエクスポートとしてエクスポートします。
export default Article;
Code language: JavaScript (javascript)
まとめ
- ネイティブブラウザFetch APIを使用して外部APIを呼び出します。