CRUD with external API in React
Tags: webdev, beginners, react, tutorial
Published: 2023-01-11 04:41:29

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:  

```JavaScript
fetch(`www.someapiurl.com/key`)
.then(response => response.json())
.then(data => console.log(data))
```
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.

```React
import {useState} from 'react';

function App(){
const [shows, setShows] = useState();
```
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`.
```React
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 
```
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`.
```React
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>)
}

```
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`.

```React
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>  );
}

```
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.  

```React
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>  );
}
```
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

-  Using the State Hook (https://reactjs.org/docs/hooks-state.html)

- Using the Effect Hook (https://reactjs.org/docs/hooks-effect.html)

- Flatiron School (https://flatironschool.com/)