Skip to content

Kapitel 12: Netzwerk-Anfragen

In diesem Kapitel lernen wir, wie man API-Aufrufe in React macht.


12.1 axios Installation und Grundlagen

📦 Installation

bash
# npm
npm install axios

# pnpm (empfohlen)
pnpm add axios

📝 Einfache GET-Anfrage

jsx
import axios from 'axios';
import { useState, useEffect } from 'react';

function App() {
  const [data, setData] = useState(null);
  const [error, setError] = useState(null);

  useEffect(() => {
    axios.get('https://api.example.com/users')
      .then(response => {
        setData(response.data);
      })
      .catch(err => {
        setError(err.message);
      });
  }, []);

  if (error) return <p>Fehler: {error}</p>;
  if (!data) return <p>Lädt...</p>;

  return (
    <ul>
      {data.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

📝 POST-Anfrage

jsx
import axios from 'axios';

function App() {
  const [name, setName] = useState('');

  const handleSubmit = () => {
    axios.post('https://api.example.com/users', { name })
      .then(response => {
        console.log('Erfolg:', response.data);
      })
      .catch(error => {
        console.error('Fehler:', error);
      });
  };

  return (
    <div>
      <input 
        type="text" 
        value={name} 
        onChange={(e) => setName(e.target.value)} 
      />
      <button onClick={handleSubmit}>Senden</button>
    </div>
  );
}

12.2 Anfragen kapseln (Request Wrapper)

🔧 Axios-Instanz erstellen

axiosInstance.js:

javascript
import axios from 'axios';

const instance = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 10000, // 10 Sekunden
  headers: {
    'Content-Type': 'application/json'
  }
});

export default instance;

🔒 Request Interceptor (Token hinzufügen)

javascript
// axiosInstance.js (fortsetzung)
instance.interceptors.request.use(
  config => {
    const token = localStorage.getItem('token');
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
  },
  error => {
    return Promise.reject(error);
  }
);

🛡️ Response Interceptor (Fehlerbehandlung)

javascript
// axiosInstance.js (fortsetzung)
instance.interceptors.response.use(
  response => response,
  error => {
    if (error.response.status === 401) {
      // Token abgelaufen → Zur Login-Seite weiterleiten
      window.location.href = '/login';
    }
    return Promise.reject(error);
  }
);

export default instance;

📦 API-Modul erstellen

api/userApi.js:

javascript
import axiosInstance from './axiosInstance';

export const userApi = {
  getUsers: () => axiosInstance.get('/users'),
  getUserById: (id) => axiosInstance.get(`/users/${id}`),
  createUser: (data) => axiosInstance.post('/users', data),
  updateUser: (id, data) => axiosInstance.put(`/users/${id}`, data),
  deleteUser: (id) => axiosInstance.delete(`/users/${id}`)
};

Verwendung:

jsx
import { userApi } from './api/userApi';

function App() {
  const [users, setUsers] = useState([]);

  useEffect(() => {
    userApi.getUsers()
      .then(response => setUsers(response.data))
      .catch(error => console.error(error));
  }, []);

  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

12.3 useEffect mit axios kombinieren

⚠️ Problem: Doppelte Anfragen

jsx
// ❌ Falsch: Kein Abhängigkeitsarray
useEffect(() => {
  axios.get('/api/data');
}); // Wird bei jedem Rendering ausgeführt!

// ✅ Richtig: Leeres Array (nur einmal)
useEffect(() => {
  axios.get('/api/data');
}, []);

// ✅ Richtig: Mit Abhängigkeiten (bei Änderung)
const [userId, setUserId] = useState(1);

useEffect(() => {
  axios.get(`/api/users/${userId}`);
}, [userId]);

🧹 Aufräumen (Cleanup)

jsx
useEffect(() => {
  const source = axios.CancelToken.source();

  axios.get('/api/data', {
    cancelToken: source.token
  });

  return () => {
    source.cancel('Componente wurde unmounted');
  };
}, []);

12.4 CORS-Probleme lösen

🤔 Was ist CORS?

CORS (Cross-Origin Resource Sharing): Browser blockiert Anfragen an eine andere Domain.

Beispiel:

Frontend: http://localhost:3000
Backend: http://api.example.com

→ CORS-Fehler!

🔧 Lösung 1: Proxy (Entwicklung)

Vite (vite.config.js):

javascript
export default {
  server: {
    proxy: {
      '/api': {
        target: 'http://api.example.com',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, '')
      }
    }
  }
};

Create React App (package.json):

json
{
  "proxy": "http://api.example.com"
}

🔧 Lösung 2: Backend-Anpassung

Node.js (Express):

javascript
const express = require('express');
const app = express();

app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', 'http://localhost:3000');
  res.header('Access-Control-Allow-Headers', 'Authorization, Content-Type');
  res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
  next();
});

app.listen(3000);

12.5 Lade- und Fehlerzustände

🔄 Loading & Error State

jsx
function App() {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    axios.get('https://api.example.com/users')
      .then(response => {
        setData(response.data);
        setLoading(false);
      })
      .catch(err => {
        setError(err.message);
        setLoading(false);
      });
  }, []);

  if (loading) return <p>Lädt...</p>;
  if (error) return <p>Fehler: {error}</p>;

  return (
    <ul>
      {data.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

🎨 Benutzerfreundlichkeit verbessern

jsx
function App() {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  const fetchData = () => {
    setLoading(true);
    setError(null);

    axios.get('https://api.example.com/users')
      .then(response => {
        setData(response.data);
        setLoading(false);
      })
      .catch(err => {
        setError(err.message);
        setLoading(false);
      });
  };

  return (
    <div>
      <button onClick={fetchData} disabled={loading}>
        {loading ? 'Lädt...' : 'Daten abrufen'}
      </button>

      {error && <p style={{ color: 'red' }}>Fehler: {error}</p>}

      {data && (
        <ul>
          {data.map(user => (
            <li key={user.id}>{user.name}</li>
          ))}
        </ul>
      )}
    </div>
  );
}

12.6 Alternative: fetch API

📝 fetch Grundlagen

jsx
useEffect(() => {
  fetch('https://api.example.com/users')
    .then(response => response.json())
    .then(data => setData(data))
    .catch(error => setError(error.message));
}, []);

🔄 fetch mit async/await

jsx
const fetchData = async () => {
  try {
    const response = await fetch('https://api.example.com/users');
    const data = await response.json();
    setData(data);
  } catch (error) {
    setError(error.message);
  }
};

useEffect(() => {
  fetchData();
}, []);

🔄 axios vs. fetch

Merkmalaxiosfetch
InstallationErforderlichEingebaut
JSON automatisch✅ Ja❌ Nein (.json())
Request/Response Interceptors✅ Ja❌ Nein
Abbrechen von Anfragen✅ Einfach⚠️ Komplex
Timeout✅ Einfach❌ Komplex

Empfehlung: Verwenden Sie axios (einfacher und mächtiger).


📝 Zusammenfassung

In diesem Kapitel haben wir gelernt:

  • ✅ axios Installation und Grundlagen
  • ✅ Anfragen kapseln (Request Wrapper)
  • ✅ Interceptors (Request & Response)
  • ✅ useEffect mit axios kombinieren
  • ✅ CORS-Probleme lösen (Proxy, Backend)
  • ✅ Lade- und Fehlerzustände verwalten
  • ✅ fetch API als Alternative

🎯 Nächste Schritte

Im nächsten Kapitel werden wir lernen:

  • Fortgeschrittene Konzepte (Performance-Optimierung)
  • memo, useMemo, useCallback
  • Error Boundaries und Lazy Loading

Bereit für fortgeschrittene Themen? → Kapitel 13: Fortgeschrittene Konzepte

Frei für alle Anfänger