DEV Community

Brandon C
Brandon C

Posted on

CRUD with external API in React

Create, Read, Update & Destroy data fetching operations with APIs in React is similar to using JavaScript but have a bit more detail with regards to states and side effects. In JavaScript, the basic format of a fetch request looks like this:

fetch(`www.someapiurl.com/key`)
.then(response => response.json())
.then(data => console.log(data))
Enter fullscreen mode Exit fullscreen mode

The result at the end of the fetch request is the information from the API. This is how it also works with React, but in order to make the page responsive we also have to update the state to reflect that information from the fetch request is added to the page or that the API has been altered.

Lets have an example of a GET fetch request. Like JavaScript, we use fetch to obtain the data from the API to use for what we want to display. React allows us to use state to make our pages dynamic in response to changes in states that we set. To utilize the dynamic changes, we first initialize the state for the data that we want as an empty array by importing and using the React hook useState() which give us our state variable shows and setter function setShows for modifying the state. Imagine our objects in the API fetch request consist of only three keys of id, title with an associated string and likes with an associated number.

import {useState} from 'react';

function App(){
const [shows, setShows] = useState();
Enter fullscreen mode Exit fullscreen mode

Because we want to fetch and display the data when our page loads, we also import and use the useEffect() hook, setting a callback function to perform the GET fetch request for our App component and setting an empty dependency array as the second argument to make sure this code only runs once to fetch the data that we initially need. Once the data is fetched, we can use the setter function setShows to set the data as our state variable shows.

import {useState, useEffect} from 'react';

function App(){
const [shows, setShows] = useState();
useEffect(()=> {
fetch(`www.someapiurl.com/key`)
.then(response => response.json())
.then(data => setShows(data));
//this gives us the data from API set as the shows array state variable
};
const allShowTitles =  shows.map( show => ( <p key={show.id} > {show.title} Likes: {show.likes} </p> ) ) 

return (  <div> <section> {allShowTitles} </section>  </div>  );
};
//this example gives us a div element for each object in the shows array with the object's key of `title` listed 
Enter fullscreen mode Exit fullscreen mode

The page will update to display the information retrieved from the external API by the time setShows changes the variable of shows at the end of the useEffect() callback, which also causes our component App to give us a <p> element for each object in shows.

For a POST request, we need to set a separate handler function to change the state in accordance to the POST request being properly processed in order to reflect the new data added to the API. The function for fetching the POST request should be assigned to the onSubmit handler for the form of the information being added to the API. For example, lets say the AddShowForm is a child of App.

function App(){
//other code from earlier is above
function handleAddShow(addedShow){
setShows([...shows , addedShow])
}

return (  <div> <section> <AddShowForm onAddShow={handleAddShow}/> </section>
<section> {allShowTitles} </section> 
</div>  );
}
-----------
function AddShowForm({onAddShow}){
const [form, setForm] = useState("");

function handleChangeForm(e){
setForm(e.target.value)
}

function handleSubmit(e){
e.preventDefault;
fetch(`www.someapiurl.com/key`, {
method: "POST",
headers: {
"Content-Type": "application/json"},
body: JSON.stringify({ title : form , likes : 0})})
.then(resp => resp.json())
.then(addedShow => onAddShow(addedShow))
}
//the contents of body undergoing .stringify should match the key & value formatting of the individual objects in the api
//the data in the second .then is the object that was added to the api at the end of the POST request 

return (<form> <input type="text" value={form} onChange={handleChangeForm} name="title" /> 
<input type="submit" onSubmit={handleSubmit} /> </form>)
}

Enter fullscreen mode Exit fullscreen mode

The function handleAddShow is located on the same component as the state variable shows and is passed down as a prop onAddShow to the child component AddShowForm where the form for making the POST request is set up. Here, we have a callback function handleSubmit that activates when the form is submitted which triggers the POST request. The response back is the object that we added to the API, which we can then use as the argument for invoking onAddShow, which is handleAddShow in App. Inside handleAddShow the setter function setShows sets the state variable in the form of an array of objects, here we use the spread operator ... on shows to pull the objects of what we already have and after ...shows is the new object obtained back from the fetch request. The state updates to reflect the change in the API and the page updates with the information of the new show we added.

PATCH requests handled in React are similar to POST requests but with the added detail of pointing to the proper object in the API, usually by id. As an example we can use a button to add likes to a show.

function App(){
//other code from earlier is above
function handleEditShow(changedShow){
const updatedShows = shows.map(show => {
if(show.id===changedShow.id){return changedShow}
return show
})
setShows(updatedShows)
}

const allShowTitles =  shows.map( show =>{

function likeClick(){
fetch(`www.someapiurl.com/key/${show.id}`, {
method: "PATCH",
headers: {
"Content-Type":"application/json",},
body: JSON.stringify({likes: show.likes + 1})
})
.then(resp=>resp.json())
.then(changedShow => handleEditShow(changedShow))
};

return ( <p key={show.id} > {show.title} Likes: {show.likes} <button onClick={likeClick}> Like! </button>  </p> ) }) 

return (  <div>
<section> {allShowTitles} </section> 
</div>  );
}

Enter fullscreen mode Exit fullscreen mode

Here we added a button and likeClick function in the .map method to each show displayed that causes a PATCH request when clicked. Each button has a different fetch request url because we interpolated every individual show id, ensuring we have the correct object to be changed. Similar to the POST request, we end the fetch request by putting the returned data changedShow as an argument in handleEditShow where we use .map on shows to create updatedShows. All unupdated shows are returned by .map while changedShow with the matching id in our conditional is returned instead of the original show with the corresponding id. updatedShows is then passed into setShows which changes the state and causes the page to update with the Likes of the show attached to the clicked button increasing by 1.

Finally, a DELETE fetch request is similar to PATCH, also with a small change.

function App(){
//other code from earlier is above
function handleDeleteShow(deletedShow){
const updatedShows = shows.filter(show => show.id!==deletedShow.id);
setShows(updatedShows)
}

const allShowTitles =  shows.map( show =>{

function deleteClick(){
fetch(`www.someapiurl.com/key/${show.id}`, {
method: "DELETE" })
.then(resp=>resp.json())
.then(handleDeleteShow(show))
};
//there is no data returned at the second .then, so we pass the original object we used to make the request into handleDeleteShow

return ( <p key={show.id} > {show.title} Likes: {show.likes} <button onClick={deleteClick}> Delete? </button>  </p> ) }) 

return (  <div>
<section> {allShowTitles} </section> 
</div>  );
}
Enter fullscreen mode Exit fullscreen mode

We add a button to each show with an onClick of deleteClick, using interpolation to give each show a unique url for the DELETE request. After the fetch, the show deleted from the API is passed into handleDeleteShow and from there .filter is used on shows to create the updatedShows variable. .filter removes the show with the associated deletedShow id from the array, and updatedShows is passed into setShows to change the state causing the page to update with the deleted show object being removed from display. Fetch requests in React makes pages more responsive allowing us to reflect server side changes in our client side pages and still works the same as with JavaScript.

Resources

Top comments (0)