April 9, 2024

HTTP PUT Method in React - fetch, Axios

In this post we'll see how to use HTTP PUT method from React applications in order to update resources on a server. We'll see how to make PUT requests using both fetch method in Fetch API and Axios with the help of examples.

fetch()- This method is used to call APIs across the network. GET is the default for fetch method.

With fetch() method you pass the URI and the body in case of PUT and it returns a promise that resolves with a Response object.

Fetch syntax for PUT method

fetch('url', {
  method: 'PUT',
  body: JSON.stringify(DATA),
  headers: {                
    'Content-type': 'application/json',                 
  },
}) 
.then(response => response.json())
.then(data => console.log(data))
.catch((error) => console.log(error.message));

Axios- It is a promise-based HTTP Client for node.js and the browser. To make a PUT request using Axios, you can use the axios.put() method.

axios.post(url[, data[, config]])

For API calls JSONPlaceholder is used which is a free fake API for testing and prototyping.

PUT request in React with fetch returning Promise

In the example there is a Component named UpdatePost. With in the component there is a form to fill post data (id, userId, title and body) to update an existing post. When the form is submitted, using fetch method a PUT request is sent with the post data to the given URI (Where postId is added to the URI 'https://jsonplaceholder.typicode.com/posts/:id'). JSONPlaceholder returns the updated post.

UpdatePost.js

import { useState } from "react";

const UpdatePost = () => {
  const [formFields, setFormFields] = useState({
    id: 0,
    title: '',
    body: '',
    userId: 0
  });
  const handleInputChange = (event) => {
    const target = event.target;
    const value = target.value;
    const name = target.name;
  
    setFormFields((prevState) => {
      return {...prevState, [name]: value};
    });
  }
  const formSubmitHandler = (event) => {
    event.preventDefault();
    const url = 'https://jsonplaceholder.typicode.com/posts/' + formFields.id;
    const putOptions = {
      method: 'PUT',
      body: JSON.stringify({...formFields}),
      headers: {'Content-type': 'application/json'}
    }
    fetch(url, putOptions)    
    .then((response) => response.json())
    .then((resData) => console.log('Updated Post ', resData))
    .catch((error) => console.log(error.message));
  }

  return(
    <div className="container">
      <h2>Post</h2>
      <form onSubmit={formSubmitHandler}>
        <div className="mb-3 mt-3">
          <label className="form-label" htmlFor="id">ID: </label>
          <input className="form-control" type="text" placeholder="Enter ID" name="id" id="id" onChange={handleInputChange}></input>
        </div>
        <div className="mb-3 mt-3">
          <label className="form-label" htmlFor="title">Title: </label>
          <input className="form-control" type="text" placeholder="Enter Title" name="title" id="title" onChange={handleInputChange}></input>
        </div>
        <div className="mb-3">
          <label className="form-label" htmlFor="body">Body: </label>
          <input className="form-control" type="text" placeholder="Enter Post Content" name="body" id="body" onChange={handleInputChange}></input>
        </div>
        <div className="mb-3">
          <label className="form-label" htmlFor="userId">User ID: </label>
          <input className="form-control" type="text" placeholder="Enter UserID" name="userId" id="userId" onChange={handleInputChange}></input>
        </div>
        <button className="btn btn-info" type="submit" onClick={formSubmitHandler}>Update Post</button>
      </form>
    </div>
  )
}

export default UpdatePost;

In the code-

  1. useState() hook is used to maintain form data.
  2. fetch() methos is called when the form is submitted, method is set as ‘PUT and as the body form data is sent (Which is the modified data for an existing post).
  3. Content-Type is set as application/json which means that the request body format is JSON.
  4. When you update a resource in JSONPlaceholder, updated post object is returned by the API.
  5. fetch() method returns a Promise, using promise chaining first the response object is converted to JSON data and then that is displayed on the console.
  6. To handle any error there is also a catch method, which just logs the error message.
  7. Note that Bootstrap 5 is used for styling here. Refer Bootstrap with React to know how to install Bootstrap in your React application.
PUT request React example

PUT request using async/await with fetch

Here is the same example which uses async/await to wait for completion of PUT request rather than using Promise with .then chaining. You can use try/catch to handle errors with async/await.

import { useState } from "react";

const UpdatePost = () => {
  const [formFields, setFormFields] = useState({
    id: 0,
    title: '',
    body: '',
    userId: 0
  });
  const handleInputChange = (event) => {
    const target = event.target;
    const value = target.value;
    const name = target.name;

    setFormFields((prevState) => {
        return {...prevState, [name]: value};
    });
  }
  const formSubmitHandler = async (event) => {
    event.preventDefault();
    try{
      const url = 'https://jsonplaceholder.typicode.com/posts/' + formFields.id;
      const putOptions = {
        method: 'PUT',
        body: JSON.stringify({...formFields}),
        headers: {'Content-type': 'application/json'}
      }
      const response = await fetch(url, putOptions);
      if(!response.ok){
        throw new Error('Error while fetching post data');
      } 
      const resData = await response.json(); 
      console.log('Updated Post ', resData)
    }catch(error){
      console.log(error.message);
    }
  }

  return(
    <div className="container">
      <h2>Post</h2>
      <form onSubmit={formSubmitHandler}>
        <div className="mb-3 mt-3">
          <label className="form-label" htmlFor="id">ID: </label>
          <input className="form-control" type="text" placeholder="Enter ID" name="id" id="id" onChange={handleInputChange}></input>
        </div>
        <div className="mb-3 mt-3">
          <label className="form-label" htmlFor="title">Title: </label>
          <input className="form-control" type="text" placeholder="Enter Title" name="title" id="title" onChange={handleInputChange}></input>
        </div>
        <div className="mb-3">
          <label className="form-label" htmlFor="body">Body: </label>
          <input className="form-control" type="text" placeholder="Enter Post Content" name="body" id="body" onChange={handleInputChange}></input>
        </div>
        <div className="mb-3">
          <label className="form-label" htmlFor="userId">User ID: </label>
          <input className="form-control" type="text" placeholder="Enter UserID" name="userId" id="userId" onChange={handleInputChange}></input>
        </div>
        <button className="btn btn-info" type="submit" onClick={formSubmitHandler}>Update Post</button>
      </form>
    </div>
  )
}

export default UpdatePost;

Few points to note in the code-

  1. formSubmitHandler method is async.
  2. You need to wait for the response so await is used with the fetch method.
  3. Await is also used while converting response data to json.
  4. Check for the response status and throw an error if response status is not ok.
  5. Code is enclosed in try/catch block to handle the thrown error.

PUT request using async/await with error message

In the above React fetch method example with async/await, error message is logged to the console. If you want to display the error to the user then you can create one more component for Error. In the UpdatePost component have the state for Error and set the Error in case one is thrown.

ErrorMessage.js

Uses the Bootstrap alert to show the error message.

const ErrorMessage = (props) => {
  return(
    <>
      <div className="alert alert-warning alert-dismissible fade show" role="alert">
        <p>{props.message}</p>
              
        <button type="button" className="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
      </div>
    </>
  )
}
export default ErrorMessage;

UpdatePost.js

Updated to have Error state variable and the logic to show error.

import { useState } from "react";
import ErrorMessage from "./ErrorMessage";

const UpdatePost = () => {
  const [formFields, setFormFields] = useState({
    id: 0,
    title: '',
    body: '',
    userId: 0
  });
  const [error, setError] = useState();
  const handleInputChange = (event) => {
    const target = event.target;
    const value = target.value;
    const name = target.name;

    setFormFields((prevState) => {
      return {...prevState, [name]: value};
    });
  }
  const formSubmitHandler = async (event) => {
    event.preventDefault();
    try{
      const url = 'https://jsonplaceholder.typicode.com/post/' + formFields.id;
      const putOptions = {
        method: 'PUT',
        body: JSON.stringify({...formFields}),
        headers: {'Content-type': 'application/json'}
      }
      const response = await fetch(url, putOptions);
      if(!response.ok){
        throw new Error('Error while fetching post data');
      } 
      const resData = await response.json(); 
      console.log('Updated Post ', resData)
    }catch(error){
      setError(error);
    }
  }
  if(error){
    return (
      <ErrorMessage message={error.message}></ErrorMessage>
    )
  }
  return(
    <div className="container">
      <h2>Post</h2>
      <form onSubmit={formSubmitHandler}>
        <div className="mb-3 mt-3">
          <label className="form-label" htmlFor="id">ID: </label>
          <input className="form-control" type="text" placeholder="Enter ID" name="id" id="id" onChange={handleInputChange}></input>
        </div>
        <div className="mb-3 mt-3">
          <label className="form-label" htmlFor="title">Title: </label>
          <input className="form-control" type="text" placeholder="Enter Title" name="title" id="title" onChange={handleInputChange}></input>
        </div>
        <div className="mb-3">
          <label className="form-label" htmlFor="body">Body: </label>
          <input className="form-control" type="text" placeholder="Enter Post Content" name="body" id="body" onChange={handleInputChange}></input>
        </div>
        <div className="mb-3">
          <label className="form-label" htmlFor="userId">User ID: </label>
          <input className="form-control" type="text" placeholder="Enter UserID" name="userId" id="userId" onChange={handleInputChange}></input>
        </div>
        <button className="btn btn-info" type="submit" onClick={formSubmitHandler}>Update Post</button>
      </form>
    </div>
  )
}

export default UpdatePost;

Now in case something goes wrong while updating an existing post you'll get an error message.

PUT Method in React - fetch, Axios

Using HTTP PUT method in React with Axios

If you want to use Axios library to make HTTP calls then the first thing is to install the Axios library.

Using npm

$ npm install axios

Using yarn

$ yarn add axios

Put request using Axios returning Promise - React Example

Uses the same example as used with fetch where we have a Component named UpdatePost. With in the component there is a form to fill post data (id, userId, title and body) to update an existing post. When the form is submitted, using axios a PUT request is sent with the post data to the given URI (Where postId is added to the URI 'https://jsonplaceholder.typicode.com/posts/:id'). JSONPlaceholder returns the updated post.

Axios serializes JavaScript objects to JSON by default so no need to explicitly do it when using Axios.

import { useState } from "react";
import ErrorMessage from "./ErrorMessage";
import axios from "axios";

const UpdatePost = () => {
  const [formFields, setFormFields] = useState({
    id: 0,
    title: '',
    body: '',
    userId: 0
  });

  const [error, setError] = useState();

  const handleInputChange = (event) => {
    const target = event.target;
    const value = target.value;
    const name = target.name;

    setFormFields((prevState) => {
      return {...prevState, [name]: value};
    });
  }

  const formSubmitHandler = (event) => {
    event.preventDefault();
    const url = 'https://jsonplaceholder.typicode.com/post/' + formFields.id;
    axios.put(url, formFields)
    .then(resData => console.log('Updated Post ', resData.data))
    .catch(error => setError(error));
  }

  if(error){
    return (
      <ErrorMessage message={error.message}></ErrorMessage>
    )
  }
  return(
    <div className="container">
      <h2>Post</h2>
      <form onSubmit={formSubmitHandler}>
        <div className="mb-3 mt-3">
          <label className="form-label" htmlFor="id">ID: </label>
          <input className="form-control" type="text" placeholder="Enter ID" name="id" id="id" onChange={handleInputChange}></input>
        </div>
        <div className="mb-3 mt-3">
          <label className="form-label" htmlFor="title">Title: </label>
          <input className="form-control" type="text" placeholder="Enter Title" name="title" id="title" onChange={handleInputChange}></input>
        </div>
        <div className="mb-3">
          <label className="form-label" htmlFor="body">Body: </label>
          <input className="form-control" type="text" placeholder="Enter Post Content" name="body" id="body" onChange={handleInputChange}></input>
        </div>
        <div className="mb-3">
          <label className="form-label" htmlFor="userId">User ID: </label>
          <input className="form-control" type="text" placeholder="Enter UserID" name="userId" id="userId" onChange={handleInputChange}></input>
        </div>
        <button className="btn btn-info" type="submit" onClick={formSubmitHandler}>Update Post</button>
      </form>
    </div>
  )
}

export default UpdatePost;

Some points to note here-

  1. Axios returns a Promise that resolves to a response object which has a data property containing the fetched data.
  2. With Axios default behavior is to reject every response that returns with a status code that falls out of the range of 2xx and treat it as an error.
  3. Error message gives a quick summary of the error message and the status it failed with.
  4. There is no change in ErrorMessage component. Please refer the above example to get the code for ErrorMessage component.

Using async/await with Axios PUT request - React Example

Here is the same example which uses async/await rather than using Promise with .then chaining. You can use try/catch to handle errors with async/await.

import { useState } from "react";
import ErrorMessage from "./ErrorMessage";
import axios from "axios";

const UpdatePost = () => {
  const [formFields, setFormFields] = useState({
    id: 0,
    title: '',
    body: '',
    userId: 0
  });

  const [error, setError] = useState();

  const handleInputChange = (event) => {
    const target = event.target;
    const value = target.value;
    const name = target.name;

    setFormFields((prevState) => {
      return {...prevState, [name]: value};
    });
  }

  const formSubmitHandler = async (event) => {
    event.preventDefault();
    try{
      const url = 'https://jsonplaceholder.typicode.com/posts/' + formFields.id;
      const resData = await axios.put(url, formFields)
      console.log('Updated Post ', resData.data)
    }catch(error){
      setError(error);
    }
  }

  if(error){
    return (
      <ErrorMessage message={error.message}></ErrorMessage>
    )
  }
  return(
    <div className="container">
      <h2>Post</h2>
      <form onSubmit={formSubmitHandler}>
        <div className="mb-3 mt-3">
          <label className="form-label" htmlFor="id">ID: </label>
          <input className="form-control" type="text" placeholder="Enter ID" name="id" id="id" onChange={handleInputChange}></input>
        </div>
        <div className="mb-3 mt-3">
          <label className="form-label" htmlFor="title">Title: </label>
          <input className="form-control" type="text" placeholder="Enter Title" name="title" id="title" onChange={handleInputChange}></input>
        </div>
        <div className="mb-3">
          <label className="form-label" htmlFor="body">Body: </label>
          <input className="form-control" type="text" placeholder="Enter Post Content" name="body" id="body" onChange={handleInputChange}></input>
        </div>
        <div className="mb-3">
          <label className="form-label" htmlFor="userId">User ID: </label>
          <input className="form-control" type="text" placeholder="Enter UserID" name="userId" id="userId" onChange={handleInputChange}></input>
        </div>
        <button className="btn btn-info" type="submit" onClick={formSubmitHandler}>Update Post</button>
      </form>
    </div>
  )
}

export default UpdatePost;

That's all for the topic HTTP PUT Method in React - fetch, Axios. If something is missing or you have something to share about the topic please write a comment.


You may also like

No comments:

Post a Comment