【学生限定】初学者のためのReact入門講座 - 勉強会資料(2024年1月9日開催)
概要
Reactの公式チュートリアルの内容をベースにReact初学者向けの解説を行います
事前準備
テキストエディタ
特にこだわりがなければ、Visual Studio Codeの利用を推奨
Node.jsのインストール(v18以上を推奨)
事前に学んでおきたいこと
JavaScript
JavaScriptは、ウェブページにインタラクティブ性を持たせるためのプログラミング言語です。たとえば、ボタンをクリックするとポップアップが表示される、フォームに入力された内容をリアルタイムで確認するなどの動的な機能を持たせることができます。最初はウェブブラウザで動作する言語として開発されましたが、現在ではサーバーサイドやモバイルアプリの開発にも使われています。
React.jsとは
- ユーザインターフェース構築のためのJavaScript ライブラリ
- 宣言的なView
- 通常のJavaScriptのDOM操作は「手続き的」
- 最近のフロントエンド・アプリ開発の主流
- Web:Angular、Vue.js、Svelteなど
- アプリ:Flutter、Swift UI、Jetpack Composeなど
- コンポーネントベース
- 一度学習すればどこでも使える(learn once, write anywhere)
- サーバーサイド(Next.js)
- モバイルアプリ・デスクトップアプリ(React Native)
- その他
- 仮想DOM
- JSライブラリの中でも特に人気
環境構築
- アプリの雛形を作成
シンプルなWebアプリの場合:Viteがおすすめ
CLIの流れに沿って簡単にアプリの雛形を構築
npm create vite@latest
- React開発者ツール(ブラウザ拡張)
Reactを学ぶ(基礎編)
①クイックスタートでReactの基礎を学ぶ
- コンポーネント
- JSX
- props
- useState(ステートフック)
②三目並べゲームの実装でReactを学ぶ
Reactを学ぶ(発展編)
トピック
- 応用的なフックを使う
- effect、ref、context、memo、reducerなど
- 非同期処理(APIとの通信)を含むアプリ
- TypeScript
- 静的型付けによる保守性・堅牢性の高いアプリケーション開発
- Next.js
- Reactを本番環境で利用するためのフレームワーク
発展的な内容を含むReactアプリを実装
- ページアクセス時にAPIからデータを取得
- 取得結果を画面に反映する
- ボタンをクリックして再取得
- TypeScriptで実装
- Next.jsで実装
import React from 'react'; type Data = { message: string; status: string; }; const HelloFetchImage: React.FC = () => { const [imageUrl, setImageUrl] = React.useState(''); // データ取得とステートの保持 const fetchData = async () => { try { const url = 'https://dog.ceo/api/breeds/image/random'; const res = await fetch(url); const data: Data = await res.json(); setImageUrl(data.message); } catch (error) { console.log(error); } }; // 副作用フック(マウント時) React.useEffect(() => { fetchData(); }, []); return ( <div> {imageUrl && <img src={imageUrl} />} <div> <button onClick={fetchData}>fetch</button> <button onClick={() => setImageUrl('')}>clear</button> </div> </div> ); }; export default function Index() { return ( <div> <HelloFetchImage /> </div> ); }
更に改善してみる
- 複数の画像表示に対応
- 初期の取得画像の数をpropsで設定できるように
- 取得する画像の数を入力で変更できるように
- loadingの表示
import React from 'react'; // { // "message": [ // "https://images.dog.ceo/breeds/lhasa/n02098413_16009.jpg", // "https://images.dog.ceo/breeds/appenzeller/n02107908_4092.jpg", // "https://images.dog.ceo/breeds/dalmatian/cooper2.jpg" // ], // "status": "success" // } type Data = { message: string[]; status: string; }; type Props = { defaultImageNums: number; }; const HelloFetchImages: React.FC<Props> = ({ defaultImageNums }) => { const [imageNums, setImageNums] = React.useState<number | ''>( defaultImageNums ); const [imageUrls, setImageUrls] = React.useState<string[]>([]); const [loading, setLoading] = React.useState(false); // データ取得とステートの保持 const fetchData = async () => { if (!imageNums || !(imageNums >= 1 && imageNums <= 50)) { alert('please select 1...50 number'); return; } setLoading(true); try { const url = `https://dog.ceo/api/breeds/image/random/${imageNums}`; const res = await fetch(url); const data: Data = await res.json(); setImageUrls(data.message); } catch (error) { console.log(error); } setLoading(false); }; const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { if (e.target.value) { setImageNums(parseInt(e.target.value)); } else { setImageNums(''); } }; // 副作用フック(マウント時) React.useEffect(() => { fetchData(); }, []); return ( <div> {loading ? 'loading....' : imageUrls.map((x) => ( <img key={x} src={x} style={{ width: 200, height: 200 }} /> ))} <div> <input type="number" value={imageNums} onChange={handleChange} max={50} min={1} /> <button onClick={fetchData}>fetch</button> <button onClick={() => setImageUrls([])}>clear</button> </div> </div> ); }; export default function Index() { return ( <div> <HelloFetchImages defaultImageNums={20} /> </div> ); }