React チートシート

ハンズオンラボで React を学ぶ

ハンズオンラボと現実世界のシナリオを通じて、React フロントエンド開発を学びましょう。LabEx は、必須のコンポーネント作成、状態管理、フック、イベント処理、パフォーマンス最適化を網羅した包括的な React コースを提供します。最新の Web アプリケーション向けに効率的で保守性の高いユーザーインターフェースを構築するスキルを習得します。

コンポーネントの作成と JSX

関数コンポーネント:function / =>

関数構文を使用してコンポーネントを作成します。

import React from 'react'

// 関数宣言
function Welcome(props) {
  return <h1>Hello, {props.name}!</h1>
}

// アロー関数
const Welcome = (props) => {
  return <h1>Hello, {props.name}!</h1>
}

// シンプルなコンポーネントの暗黙的な返却
const Greeting = ({ name }) => <h1>Hello, {name}!</h1>

クラスコンポーネント:class extends React.Component

ES6 クラス構文を使用してコンポーネントを作成します。

import React, { Component } from 'react'

class Welcome extends Component {
  render() {
    return <h1>Hello, {this.props.name}!</h1>
  }
}

// constructor 付き
class Counter extends Component {
  constructor(props) {
    super(props)
    this.state = { count: 0 }
  }
  render() {
    return <div>Count: {this.state.count}</div>
  }
}

JSX 要素:<element>

JavaScript 内で HTML のような構文を記述します。

// JSX 要素
const element = <h1>Hello, world!</h1>

// 式を含む JSX
const name = 'John'
const greeting = <h1>Hello, {name}!</h1>

// 複数行の JSX
const element = (
  <div>
    <h1>Welcome!</h1>
    <p>Good to see you here.</p>
  </div>
)

コンポーネントのエクスポート:export default / export

コンポーネントをエクスポートして、他のファイルで使用できるようにします。

// デフォルトエクスポート
export default function App() {
  return <div>My App</div>
}

// 名前付きエクスポート
export const Button = () => <button>Click me</button>

コンポーネントのインポート:import

他のファイルからコンポーネントをインポートします。

// デフォルトコンポーネントのインポート
import App from './App'

// 名前付きコンポーネントのインポート
import { Button } from './Button'

// 複数のコンポーネントのインポート
import React, { useState, useEffect } from 'react'

// エイリアス付きのインポート
import { Button as MyButton } from './Button'

フラグメント:<React.Fragment> / <>

余分な DOM ノードを追加せずに要素をグループ化します。

// React.Fragment を使用
return (
  <React.Fragment>
    <h1>Title</h1>
    <p>Description</p>
  </React.Fragment>
)

// 短縮構文を使用
return (
  <>
    <h1>Title</h1>
    <p>Description</p>
  </>
)

Props とコンポーネントの構造

Props: props.name

親から子コンポーネントへデータを渡します。

// props の受信
function Welcome(props) {
  return <h1>Hello, {props.name}!</h1>
}

// props の分割代入
function Welcome({ name, age }) {
  return (
    <h1>
      Hello, {name}! You are {age} years old.
    </h1>
  )
}

// デフォルト props
function Welcome({ name = 'Guest' }) {
  return <h1>Hello, {name}!</h1>
}
クイズ

ログインしてこのクイズに回答し、学習の進捗を追跡できます

React で親コンポーネントから子コンポーネントにデータを渡すにはどうすればよいですか?
state 変数を使用する
props を使用する
ref を使用する
context API を使用する

PropTypes: Component.propTypes

コンポーネントに渡された props を検証します(prop-types パッケージが必要)。

import PropTypes from 'prop-types'

function Welcome({ name, age }) {
  return (
    <h1>
      Hello, {name}! Age: {age}
    </h1>
  )
}

Welcome.propTypes = {
  name: PropTypes.string.isRequired,
  age: PropTypes.number,
}

Welcome.defaultProps = {
  age: 18,
}

Children: props.children

コンポーネントの開始タグと終了タグの間で渡されたコンテンツにアクセスします。

// children を使用するコンポーネント
function Card({ children }) {
  return <div className="card">{children}</div>
}

// 使用例
;<Card>
  <h2>Title</h2>
  <p>Content here</p>
</Card>

状態管理とフック

useState フック:useState()

関数コンポーネントに状態を追加します。

import React, { useState } from 'react'

function Counter() {
  const [count, setCount] = useState(0)
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  )
}

// 複数の状態変数
function Form() {
  const [name, setName] = useState('')
  const [email, setEmail] = useState('')
}
クイズ

ログインしてこのクイズに回答し、学習の進捗を追跡できます

useState(0) は何を返しますか?
状態値とそれを更新する関数の配列
状態値のみ
状態を更新するための関数
状態を設定するだけで何も返さない

useEffect フック:useEffect()

関数コンポーネントで副作用を実行します。

import React, { useState, useEffect } from 'react'

function Timer() {
  const [count, setCount] = useState(0)

  // すべてのレンダリング後に実行されるエフェクト
  useEffect(() => {
    document.title = `Count: ${count}`
  })

  // クリーンアップ付きのエフェクト
  useEffect(() => {
    const timer = setInterval(() => setCount((c) => c + 1), 1000)
    return () => clearInterval(timer)
  }, [])
}
クイズ

ログインしてこのクイズに回答し、学習の進捗を追跡できます

useEffect(() => {...}, [])の空の依存関係配列は何を意味しますか?
エフェクトはすべてのレンダリングで実行される
エフェクトは実行されない
エフェクトは 2 回実行される
エフェクトは最初のレンダリング後に一度だけ実行される

クラスの状態:this.state / setState()

クラスコンポーネントで状態を管理します。

class Counter extends React.Component {
  constructor(props) {
    super(props)
    this.state = { count: 0 }
  }
  increment = () => {
    this.setState({ count: this.state.count + 1 })
  }
  render() {
    return (
      <div>
        <p>Count: {this.state.count}</p>
        <button onClick={this.increment}>Increment</button>
      </div>
    )
  }
}

カスタムフック:use...

再利用可能な状態ロジックを作成します。

// カスタムフック
function useCounter(initialValue = 0) {
  const [count, setCount] = useState(initialValue)
  const increment = () => setCount(count + 1)
  const decrement = () => setCount(count - 1)
  const reset = () => setCount(initialValue)
  return { count, increment, decrement, reset }
}

// 使用例
function Counter() {
  const { count, increment, decrement, reset } = useCounter(0)
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>+</button>
      <button onClick={decrement}>-</button>
      <button onClick={reset}>Reset</button>
    </div>
  )
}

イベント処理

クイズ

ログインしてこのクイズに回答し、学習の進捗を追跡できます

React における PropTypes の目的は何ですか?
コンポーネントに渡される props の型を検証すること
コンポーネントのパフォーマンスを向上させること
コンポーネントを自動的にスタイリングすること
コンポーネントを高速化すること

クリックイベント:onClick

ボタンのクリックや要素の操作を処理します。

function Button() {
  const handleClick = () => {
    alert('Button clicked!')
  }
  return <button onClick={handleClick}>Click me</button>
}

// インラインイベントハンドラ
function Button() {
  return <button onClick={() => alert('Clicked!')}>Click me</button>
}

// パラメータを渡す
function Button() {
  const handleClick = (message) => {
    alert(message)
  }
  return <button onClick={() => handleClick('Hello!')}>Click me</button>
}

フォームイベント:onChange / onSubmit

フォームの入力と送信を処理します。

function Form() {
  const [value, setValue] = useState('')
  const handleChange = (e) => {
    setValue(e.target.value)
  }
  const handleSubmit = (e) => {
    e.preventDefault()
    console.log('Submitted:', value)
  }
  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        value={value}
        onChange={handleChange}
        placeholder="Enter text"
      />
      <button type="submit">Submit</button>
    </form>
  )
}

イベントオブジェクト:event.target / event.preventDefault()

イベントプロパティにアクセスし、デフォルトの動作を制御します。

function handleInput(event) {
  console.log('Input value:', event.target.value)
  console.log('Input name:', event.target.name)
}

function handleFormSubmit(event) {
  event.preventDefault() // フォームの送信を防止
  console.log('Form submitted')
}

// イベントの委譲
function List() {
  const handleClick = (event) => {
    if (event.target.tagName === 'BUTTON') {
      console.log('Button clicked:', event.target.textContent)
    }
  }
  return (
    <div onClick={handleClick}>
      <button>Button 1</button>
      <button>Button 2</button>
    </div>
  )
}

キーボードイベント:onKeyDown / onKeyUp

キーボード操作に応答します。

function KeyboardHandler() {
  const handleKeyDown = (event) => {
    if (event.key === 'Enter') {
      console.log('Enter key pressed')
    }
    if (event.ctrlKey && event.key === 's') {
      event.preventDefault()
      console.log('Ctrl+S pressed')
    }
  }
  return <input onKeyDown={handleKeyDown} placeholder="Type here..." />
}

条件付きレンダリング

条件演算子:&& / ?:

条件に基づいて要素を表示/非表示にします。

function Greeting({ user }) {
  return (
    <div>
      {user && <h1>Welcome, {user.name}!</h1>}
      {!user && <h1>Please log in</h1>}
    </div>
  )
}

// 三項演算子
function Status({ isOnline }) {
  return <div>User is {isOnline ? 'online' : 'offline'}</div>
}

If/Elseロジック: if

複雑な条件のために従来の JavaScript ロジックを使用します。

function UserProfile({ user, isAdmin }) {
  if (!user) {
    return <div>Loading...</div>
  }
  if (isAdmin) {
    return <AdminPanel user={user} />
  }
  return <UserPanel user={user} />
}

// 早期リターンパターン
function Component({ data }) {
  if (!data) return null
  if (data.error) return <ErrorMessage />
  return <DataDisplay data={data} />
}

Switch 文:switch

複数の条件を効率的に処理します。

function StatusIcon({ status }) {
  switch (status) {
    case 'loading':
      return <Spinner />
    case 'success':
      return <CheckIcon />
    case 'error':
      return <ErrorIcon />
    default:
      return null
  }
}

動的スタイル:条件付き CSS

コンポーネントの状態や props に基づいてスタイルを適用します。

function Button({ variant, disabled }) {
  const className = `btn ${variant} ${disabled ? 'disabled' : ''}`
  return (
    <button
      className={className}
      style={{
        backgroundColor: variant === 'primary' ? 'blue' : 'gray',
        opacity: disabled ? 0.5 : 1,
      }}
      disabled={disabled}
    >
      Click me
    </button>
  )
}

リストのレンダリングとキー

Map 関数:array.map()

配列データからコンポーネントのリストをレンダリングします。

function TodoList({ todos }) {
  return (
    <ul>
      {todos.map((todo) => (
        <li key={todo.id}>{todo.text}</li>
      ))}
    </ul>
  )
}

// インデックス付き(可能な限り避ける)
function ItemList({ items }) {
  return (
    <ul>
      {items.map((item, index) => (
        <li key={index}>{item}</li>
      ))}
    </ul>
  )
}

キー: key prop

レンダリングを最適化するために、リスト項目に一意の識別子を提供します。

// 良い例:一意の ID を使用
function UserList({ users }) {
  return (
    <ul>
      {users.map((user) => (
        <li key={user.id}>
          <UserCard user={user} />
        </li>
      ))}
    </ul>
  )
}

// 複合キーの作成
function CommentList({ comments }) {
  return (
    <div>
      {comments.map((comment) => (
        <Comment key={`${comment.postId}-${comment.id}`} comment={comment} />
      ))}
    </div>
  )
}

Filter と Map: 配列メソッド

リストをレンダリングする前に配列を処理します。

function TaskList({ tasks, showCompleted }) {
  const filteredTasks = showCompleted
    ? tasks
    : tasks.filter((task) => !task.completed)
  return (
    <ul>
      {filteredTasks.map((task) => (
        <li key={task.id} className={task.completed ? 'completed' : ''}>
          {task.title}
        </li>
      ))}
    </ul>
  )
}

空の状態:空の配列の処理

リストが空の場合に適切なコンテンツを表示します。

function ProductList({ products }) {
  if (products.length === 0) {
    return <div>No products found.</div>
  }
  return (
    <div>
      {products.map((product) => (
        <ProductCard key={product.id} product={product} />
      ))}
    </div>
  )
}

パフォーマンスの最適化

React.memo: React.memo()

関数コンポーネントの不要な再レンダリングを防ぎます。

const ExpensiveComponent = React.memo(function ExpensiveComponent({ data }) {
  return <div>{/* 複雑なレンダリングロジック */}</div>
})

// カスタム比較付き
const MyComponent = React.memo(
  function MyComponent({ user }) {
    return <div>{user.name}</div>
  },
  (prevProps, nextProps) => {
    return prevProps.user.id === nextProps.user.id
  },
)

useMemo フック:useMemo()

高負荷な計算をメモ化します。

function ExpensiveList({ items, searchTerm }) {
  const filteredItems = useMemo(() => {
    return items.filter((item) =>
      item.name.toLowerCase().includes(searchTerm.toLowerCase()),
    )
  }, [items, searchTerm])
  return (
    <ul>
      {filteredItems.map((item) => (
        <li key={item.id}>{item.name}</li>
      ))}
    </ul>
  )
}

useCallback フック:useCallback()

関数参照をメモ化して、不要な再レンダリングを防ぎます。

function Parent({ items }) {
  const [count, setCount] = useState(0)
  const handleItemClick = useCallback((itemId) => {
    console.log('Item clicked:', itemId)
  }, []) // 空の依存関係配列
  return (
    <div>
      <button onClick={() => setCount(count + 1)}>Count: {count}</button>
      <ItemList items={items} onItemClick={handleItemClick} />
    </div>
  )
}

遅延ロード:React.lazy() / Suspense

バンドルサイズを削減するために、必要なときにのみコンポーネントをロードします。

const LazyComponent = React.lazy(() => import('./LazyComponent'))

function App() {
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <LazyComponent />
      </Suspense>
    </div>
  )
}

コンポーネント間の通信

Props Down: 親から子へ

親コンポーネントから子コンポーネントへデータを渡します。

function Parent() {
  const [user, setUser] = useState({ name: 'John', age: 30 })
  return (
    <div>
      <ChildComponent user={user} />
      <AnotherChild userName={user.name} />
    </div>
  )
}

function ChildComponent({ user }) {
  return <div>Hello, {user.name}!</div>
}

Callbacks Up: 子から親へ

子コンポーネントから親コンポーネントへデータを送り返します。

function Parent() {
  const [message, setMessage] = useState('')
  const handleChildMessage = (msg) => {
    setMessage(msg)
  }
  return (
    <div>
      <p>Message: {message}</p>
      <Child onMessage={handleChildMessage} />
    </div>
  )
}

function Child({ onMessage }) {
  return (
    <button onClick={() => onMessage('Hello from child!')}>Send Message</button>
  )
}

Context API: createContext / useContext

プロップドリリングなしで複数のコンポーネント間で状態を共有します。

const UserContext = React.createContext()

function App() {
  const [user, setUser] = useState({ name: 'John' })
  return (
    <UserContext.Provider value={{ user, setUser }}>
      <Header />
      <Main />
    </UserContext.Provider>
  )
}

function Header() {
  const { user } = useContext(UserContext)
  return <h1>Welcome, {user.name}!</h1>
}

Refs: useRef / forwardRef

DOM 要素にアクセスしたり、変更可能な値を格納したりします。

function TextInput() {
  const inputRef = useRef(null)
  const focusInput = () => {
    inputRef.current.focus()
  }
  return (
    <div>
      <input ref={inputRef} type="text" />
      <button onClick={focusInput}>Focus Input</button>
    </div>
  )
}

// Ref の転送
const FancyInput = forwardRef((props, ref) => (
  <input className="fancy" ref={ref} {...props} />
))

開発ツールとデバッグ

React DevTools: ブラウザ拡張機能

React コンポーネントをデバッグし、コンポーネントツリーを検査します。

// React DevTools ブラウザ拡張機能をインストール
// Components タブ:コンポーネント階層の検査
// Profiler タブ:パフォーマンスの測定

// コンソールデバッグ
function MyComponent(props) {
  console.log('MyComponent props:', props)
  console.log('MyComponent rendered')
  return <div>{props.children}</div>
}

エラー境界線:componentDidCatch

コンポーネントツリー内の JavaScript エラーをキャッチし、フォールバック UI を表示します。

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props)
    this.state = { hasError: false }
  }
  static getDerivedStateFromError(error) {
    return { hasError: true }
  }
  componentDidCatch(error, errorInfo) {
    console.log('Error caught:', error, errorInfo)
  }
  render() {
    if (this.state.hasError) {
      return <h1>Something went wrong.</h1>
    }
    return this.props.children
  }
}

Strict Mode: React.StrictMode

開発中に、追加のチェックと警告を有効にします。

import React from 'react'
import ReactDOM from 'react-dom'

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

プロファイリング:パフォーマンス測定

コンポーネントのパフォーマンスを測定し、ボトルネックを特定します。

// React DevTools Profiler の使用
// プロファイル対象のコンポーネントをラップ
import { Profiler } from 'react'

function onRenderCallback(id, phase, actualDuration) {
  console.log('Component', id, 'took', actualDuration, 'ms')
}

;<Profiler id="App" onRender={onRenderCallback}>
  <App />
</Profiler>

React のインストールとセットアップ

Create React App: npx create-react-app

新しい React プロジェクトを迅速にブートストラップします。

# 新しいReactアプリの作成
npx create-react-app my-app
cd my-app

# 開発サーバーの起動
npm start

# 本番環境向けビルド
npm run build

# テストの実行
npm test

Vite: npm create vite@latest

React プロジェクト向けの高速なビルドツールと開発サーバー。

# 新しいVite Reactアプリの作成
npm create vite@latest my-react-app -- --template react
cd my-react-app
npm install

# 開発サーバーの起動
npm run dev

# 本番環境向けビルド
npm run build

手動セットアップ/インポート

既存のプロジェクトに React を追加するか、CDN を使用します。

# ReactとReactDOMのインストール
npm install react react-dom

# 開発用
npm install --save-dev @vitejs/plugin-react
// 基本的な React インポート
import React from 'react'
import ReactDOM from 'react-dom/client'

// DOM へのレンダリング
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(<App />)

高度なパターンと機能

高階コンポーネント (HOC)

コンポーネントをラップすることで、コンポーネントロジックを再利用します。

function withLoading(WrappedComponent) {
  return function WithLoadingComponent(props) {
    if (props.isLoading) {
      return <div>Loading...</div>
    }
    return <WrappedComponent {...props} />
  }
}

// 使用例
const UserListWithLoading = withLoading(UserList)
;<UserListWithLoading users={users} isLoading={loading} />

Render Props パターン

props の値として関数を使用することで、コンポーネント間でコードを共有します。

function DataFetcher({ render, url }) {
  const [data, setData] = useState(null)
  const [loading, setLoading] = useState(true)
  useEffect(() => {
    fetch(url)
      .then((res) => res.json())
      .then((data) => {
        setData(data)
        setLoading(false)
      })
  }, [url])
  return render({ data, loading })
}

// 使用例
;<DataFetcher
  url="/api/users"
  render={({ data, loading }) =>
    loading ? <Spinner /> : <UserList users={data} />
  }
/>

複合コンポーネント

協調して機能する一貫したユニットとしてコンポーネントを作成します。

function Tabs({ children, activeTab }) {
  return (
    <div className="tabs">
      {React.Children.map(children, (child, index) =>
        React.cloneElement(child, { isActive: index === activeTab }),
      )}
    </div>
  )
}

function Tab({ children, isActive }) {
  return <div className={`tab ${isActive ? 'active' : ''}`}>{children}</div>
}

// 使用例
;<Tabs activeTab={0}>
  <Tab>Tab 1 Content</Tab>
  <Tab>Tab 2 Content</Tab>
</Tabs>

Portal: ReactDOM.createPortal()

子要素を親コンポーネントの階層外の DOM ノードにレンダリングします。

import ReactDOM from 'react-dom'

function Modal({ children, isOpen }) {
  if (!isOpen) return null
  return ReactDOM.createPortal(
    <div className="modal-overlay">
      <div className="modal">{children}</div>
    </div>,
    document.getElementById('modal-root'),
  )
}

継承よりもコンポジション

クラスを拡張する代わりに、コンポジションパターンを使用します。

// 良い例:コンポジション
function Button({ variant, children, ...props }) {
  return (
    <button className={`btn btn-${variant}`} {...props}>
      {children}
    </button>
  )
}

function IconButton({ icon, children, ...props }) {
  return (
    <Button {...props}>
      <Icon name={icon} />
      {children}
    </Button>
  )
}

コンポーネントパターン:柔軟な API

柔軟で使いやすいコンポーネント API を設計します。

// 柔軟な Card コンポーネント
function Card({ header, children, footer, variant = 'default' }) {
  return (
    <div className={`card card-${variant}`}>
      {header && <div className="card-header">{header}</div>}
      <div className="card-body">{children}</div>
      {footer && <div className="card-footer">{footer}</div>}
    </div>
  )
}

// 使用例
;<Card header={<h3>Title</h3>} footer={<Button>Action</Button>}>
  Card content here
</Card>

関連リンク