HOWTO · React
Different Ways to Make a POST Request in React
Learn how to send JSON data from React with Fetch, Axios, jQuery AJAX, React Query, or XMLHttpRequest, and handle responses and request errors.
On this page
React does not require a particular HTTP client. For a new application, start with the browser’s built-in fetch(); choose axios if you want its response and error conveniences, keep jQuery AJAX when maintaining a codebase that already uses jQuery, or use React Query to manage mutation state. The examples below send the same illustrative profile payload to https://api.example.test/profiles. This is a placeholder endpoint, not a live service; replace it with an API you control.
Using Fetch API
fetch() is built into modern browsers and works well for a small POST request. Set the method to POST, identify the JSON body with a Content-Type header, and serialize the object with JSON.stringify(). The function below accepts a fetch implementation so its request construction and response handling are self-contained. Its local response is a demonstration; it does not contact a server.
async function createProfile(fetchImpl) {
const response = await fetchImpl('https://api.example.test/profiles', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'Sam Lee', role: 'developer' }),
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return response.json();
}
const demoFetch = async (url, options) => ({
ok: true,
json: async () => ({ url, method: options.method, profile: JSON.parse(options.body) }),
});
createProfile(demoFetch).then((result) => console.log(result.profile.name, result.method));
The returned body nests the submitted profile under profile, so the final line reads result.profile.name. In a component, call the same request logic from a submit handler and use component state to show the result. Check response.ok before parsing a success body: Fetch fulfills its promise for HTTP responses such as 404 or 500, while network failures reject it. A server may return no JSON body, so parse JSON only when that is the response format your API promises. This demonstration uses an in-memory response rather than contacting the placeholder endpoint.
Using Axios
In a bundled application, install axios with your package manager and import it from the package. Its post(url, data) method accepts a JavaScript object and serializes it as JSON; the resolved response places the server body in response.data. The browser example below imports modules from esm.sh to keep the source self-contained; it is illustrative and has not been executed here.
<div id="root"></div>
<script type="module">
import React, { useState } from 'https://esm.sh/react';
import { createRoot } from 'https://esm.sh/react-dom/client';
import axios from 'https://esm.sh/axios';
function ProfileForm() {
const [profile, setProfile] = useState(null);
const [error, setError] = useState('');
async function handleSubmit(event) {
event.preventDefault();
setError('');
try {
const response = await axios.post('https://api.example.test/profiles', {
name: 'Sam Lee',
role: 'developer',
});
setProfile(response.data.profile ?? response.data);
} catch (requestError) {
const message = requestError.response
? `Request failed: ${requestError.response.status}`
: 'Network request failed';
setError(message);
}
}
return React.createElement('form', { onSubmit: handleSubmit },
React.createElement('button', { type: 'submit' }, 'Create profile'),
profile && React.createElement('p', null, `Created ${profile.name}`),
error && React.createElement('p', { role: 'alert' }, error));
}
createRoot(document.getElementById('root')).render(React.createElement(ProfileForm));
</script>
Axios rejects for non-success HTTP statuses by default. The handler distinguishes a server response from a request with no response and stores either result in React state, rather than returning an error as though it were a successful profile. Axios is useful when its interceptors, shared configuration, or response transformation simplify a larger application. For one request, Fetch avoids adding a dependency.
Using jQuery AJAX
jQuery AJAX is most practical when maintaining an application that already loads jQuery. In a React component, keep React responsible for rendering and update state from the AJAX callbacks; avoid using jQuery to mutate DOM nodes that React owns. This browser and package example is illustrative and has not been executed here. Add jQuery to the app using its existing package setup before using the component.
<div id="root"></div>
<script type="module">
import React, { useState } from 'https://esm.sh/react';
import { createRoot } from 'https://esm.sh/react-dom/client';
import $ from 'https://esm.sh/jquery';
function ProfileForm() {
const [profile, setProfile] = useState(null);
const [error, setError] = useState('');
function handleSubmit(event) {
event.preventDefault();
setError('');
$.ajax({
url: 'https://api.example.test/profiles',
type: 'POST',
contentType: 'application/json',
dataType: 'json',
data: JSON.stringify({ name: 'Sam Lee', role: 'developer' }),
success: (data) => setProfile(data.profile ?? data),
error: (xhr, status, requestError) => {
setError(xhr.responseJSON?.message || requestError || status);
},
});
}
return React.createElement('form', { onSubmit: handleSubmit },
React.createElement('button', { type: 'submit' }, 'Create profile'),
profile && React.createElement('p', null, `Created ${profile.name}`),
error && React.createElement('p', { role: 'alert' }, error));
}
createRoot(document.getElementById('root')).render(React.createElement(ProfileForm));
</script>
Here contentType describes the JSON request body, while dataType tells jQuery to parse the expected JSON response. The callbacks update React state for success and failure. These options do not guarantee that the server accepts the request or returns the promised format. For new React work, Fetch or Axios usually fits more naturally and avoids jQuery’s extra dependency.
Using React Query
React Query can manage a POST as a mutation when the component needs shared server-state behavior or clear pending, success, and error UI. Keep the network request in a mutation function, trigger it from the user’s submit action, and render the state exposed by the installed library version. The following is a version-independent workflow, not a copyable hook signature: submit the profile payload → run the POST mutation → show pending feedback → display the returned profile or an error. This conceptual example has not been executed; consult the React Query documentation for the version already installed before choosing package names, imports, hook signatures, or state-property names.
A mutation is a better fit for an action that changes server data than a query used to read data. After success, update or invalidate related cached data according to the application’s data flow. Keep the endpoint and JSON payload consistent with the other examples, and do not assume that a successful request automatically refreshes every view.
Using XMLHttpRequest
XMLHttpRequest is a browser API that can send a JSON POST without a request library. It is distinct from Fetch, even though both are browser-provided options. This event-driven browser example is illustrative and has not been executed in the configured runtime.
<div id="root"></div>
<script type="module">
import React, { useState } from 'https://esm.sh/react';
import { createRoot } from 'https://esm.sh/react-dom/client';
function ProfileForm() {
const [profile, setProfile] = useState(null);
const [error, setError] = useState('');
function handleSubmit(event) {
event.preventDefault();
setProfile(null);
setError('');
const request = new XMLHttpRequest();
request.open('POST', 'https://api.example.test/profiles');
request.setRequestHeader('Content-Type', 'application/json');
request.addEventListener('load', () => {
if (request.status < 200 || request.status >= 300) {
setError(`Request failed: ${request.status}`);
return;
}
try {
const data = JSON.parse(request.responseText);
setProfile(data.profile ?? data);
} catch {
setError('The server response was not valid JSON');
}
});
request.addEventListener('error', () => setError('Network request failed'));
request.send(JSON.stringify({ name: 'Sam Lee', role: 'developer' }));
}
return React.createElement('form', { onSubmit: handleSubmit },
React.createElement('button', { type: 'submit' }, 'Create profile'),
profile && React.createElement('p', null, `Created ${profile.name}`),
error && React.createElement('p', { role: 'alert' }, error));
}
createRoot(document.getElementById('root')).render(React.createElement(ProfileForm));
</script>
The load handler covers HTTP responses, so it checks the status before parsing the body. The error handler covers network failures. Both paths update React state; production code should also abort or ignore an outstanding request if the component unmounts. For most new code, Fetch is simpler; XMLHttpRequest can be useful when maintaining code that already depends on it or needs its event-based interface.
Conclusion
Use Fetch for a straightforward browser POST, Axios when its client features help, and React Query when mutation state and cache coordination matter. Keep jQuery AJAX for existing jQuery code, and choose XMLHttpRequest when its event-based API suits the application. In every case, match the body and headers to the server’s API, check the response, and show request status in the React UI.
FAQ
What does a POST request do?
POST sends data to a server for processing, such as creating a resource. The API defines what the submitted data means; POST is not limited to updating an existing resource.
Should I use Fetch or Axios?
Fetch is built into modern browsers and is enough for many requests, but your code must check the HTTP status because an HTTP error response does not reject its promise. Axios offers a consistent response object and rejects non-success HTTP statuses by default. Choose based on the needs of your application and its existing dependencies.
Can I use jQuery with React?
Yes, particularly when maintaining an application that already uses jQuery. Let React own its rendered DOM and use the AJAX callbacks to update React state. For new code, Fetch or Axios is generally a more direct fit.
What does React Query add to a POST request?
It treats the request as a mutation and helps connect pending, success, and error states with server-state management. Its exact API depends on the installed version, so use that version’s documentation for implementation details.
How should I handle POST errors?
Check HTTP status and response data according to the server’s contract, and provide a visible error state. With Fetch, check response.ok because HTTP failures still produce a response. With Axios, handle the rejected request and distinguish a server response from a network failure. With jQuery or XMLHttpRequest, use their error or network events and update React state.