Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

Sending a POST Request in React Native

Sending a POST Request

~9 Min. Lesezeit Zuletzt aktualisiert am August 8, 2026

While GET retrieves data, POST sends data TO a server – the classic case for forms: registration, contact forms, creating a new record. This time using the built-in fetch() API instead of Axios, for a direct comparison of the two approaches.

1. Description

With fetch(), method, headers, and body must be specified EXPLICITLY – unlike Axios' axios.post(url, data), fetch() handles neither the Content-Type header nor the JSON serialization of the body automatically.

2. Short example

const response = await fetch('https://api.example.com/contacts', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ name: 'Anna' }),
});
const data = await response.json();

3. Complete project: a feedback form

npx create-expo-app post-request-demo
cd post-request-demo
App.js
import { useState } from 'react';
import { View, TextInput, Button, Text, ActivityIndicator, StyleSheet } from 'react-native';

export default function App() {
  const [name, setName] = useState('');
  const [message, setMessage] = useState('');
  const [submitting, setSubmitting] = useState(false);
  const [result, setResult] = useState(null);

  async function submit() {
    setSubmitting(true);
    setResult(null);
    try {
      const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ title: name, body: message }),
      });

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

      const data = await response.json();
      setResult(`Sent! New ID: ${data.id}`);
      setName('');
      setMessage('');
    } catch (error) {
      setResult(`Error: ${error.message}`);
    } finally {
      setSubmitting(false);
    }
  }

  return (
    <View style={styles.container}>
      <TextInput
        style={styles.input}
        placeholder="Your name"
        value={name}
        onChangeText={setName}
      />
      <TextInput
        style={[styles.input, styles.multiline]}
        placeholder="Your message"
        value={message}
        onChangeText={setMessage}
        multiline
      />
      <Button
        title="Submit"
        onPress={submit}
        disabled={submitting || !name || !message}
      />
      {submitting && <ActivityIndicator style={styles.spinner} />}
      {result && <Text style={styles.result}>{result}</Text>}
    </View>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, paddingTop: 60, paddingHorizontal: 24 },
  input: { borderWidth: 1, borderColor: '#d1d5db', borderRadius: 8, padding: 10, marginBottom: 12 },
  multiline: { height: 100, textAlignVertical: 'top' },
  spinner: { marginTop: 16 },
  result: { marginTop: 16, textAlign: 'center' },
});

4. Explanation

  • headers: {{ 'Content-Type': 'application/json' }} is MANDATORY with fetch() so the server correctly interprets the body as JSON – without this header, it's often treated as plain text.
  • body: JSON.stringify(...)fetch() does NOT serialize automatically, unlike Axios; the object must be manually converted into a JSON string.
  • response.ok checks whether the status code is in the 200–299 range – fetch() does NOT throw an error automatically on a 4xx/5xx status (unlike Axios); you must check this yourself.
  • disabled={{submitting || !name || !message}} prevents both duplicate submissions during an in-flight request AND empty form submissions in a single expression.

5. Outputs

Ausgabe
Two input fields (name, multiline message) and a "Submit" button that stays disabled (grayed out) until both fields are filled. After tapping, a loading spinner briefly appears, then green text "Sent! New ID: 101" and both fields are cleared.