Day 02 Core Concepts

Calling the Claude API from React

Connect your React chat app to the Claude API. Handle async requests, loading states, and errors in a React component.

~1 hour Hands-on Precision AI Academy

Today's Objective

Learn the core concepts of Calling the Claude API from React and apply them in practical exercises.

01

API Architecture: Never Call AI APIs Directly From the Browser

Your API key would be visible to anyone who opened DevTools. Always route AI API calls through a backend proxy — even a simple one.

bash
bash
# Install a simple Express server
npm install express cors
npm install -D nodemon
javascript — server.js
javascript — server.js
const express = require('express');
const cors = require('cors');

const app = express();
app.use(cors({ origin: 'http://localhost:5173' }));
app.use(express.json());

const Anthropic = require('@anthropic-ai/sdk');
const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });

app.post('/api/chat', async (req, res) => {
  const { messages } = req.body;

  try {
    const response = await client.messages.create({
      model: 'claude-3-haiku-20240307',
      max_tokens: 1024,
      messages: messages,  // array of {role, content}
    });
    res.json({ content: response.content[0].text });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

app.listen(3001, () => console.log('API server on :3001'));
bash
bash
# In a .env file (git-ignored)
ANTHROPIC_API_KEY=sk-ant-...

# Run the server
node server.js
02

Calling the API From React

jsx
jsx
async function sendMessage(userText) {
  const userMsg = { role: 'user', content: userText };
  setMessages(prev => [...prev, userMsg]);
  setIsLoading(true);
  setError(null);

  try {
    const response = await fetch('http://localhost:3001/api/chat', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        messages: [...messages, userMsg]  // send full history
      })
    });

    if (!response.ok) throw new Error(`HTTP ${response.status}`);

    const data = await response.json();
    setMessages(prev => [...prev, {
      id: Date.now(),
      role: 'assistant',
      content: data.content
    }]);
  } catch (err) {
    setError('Failed to get response. Try again.');
  } finally {
    setIsLoading(false);  // always clear loading, even on error
  }
}
⚠️
Pass the full message history. Claude is stateless — it doesn't remember previous messages unless you send them. Always include the full messages array including the new user message.
03

Loading State UI

jsx
jsx
function TypingIndicator() {
  return (
    
); } // In the messages render: {messages.map(msg => )} {isLoading && } {error &&
{error}
}
04

useCallback and Performance

jsx
jsx
import { useState, useCallback } from 'react';

// Without useCallback, sendMessage recreates on every render
// ChatInput would re-render unnecessarily
const sendMessage = useCallback(async (userText) => {
  // ... the function body
}, [messages]);  // only recreate when messages changes

Supporting References & Reading

Go deeper with these external resources.

Docs
Calling the Claude API: Real AI Responses Official documentation for react ai.
GitHub
Calling the Claude API: Real AI Responses Open source examples and projects for Calling the Claude API: Real AI Responses
MDN
MDN Web Docs Comprehensive web technology reference

Day 2 Checkpoint

Before moving on, confirm understanding of these key concepts:

Continue To Day 3
Day 3 of the React + AI in 5 Days course