Fetching in react
Fetching in React is similar to fetching in JavaScript.
The way we handle those requests is different due to State hooks and the way we render things to the DOM.
Note: I will be using a pessimistic approach to rendering elements - by only updating state from successful fetches.
CRUD requests
GET
In react, we cannot simply have our fetch request in a function.
If we do that, the page will re-render in an infinite loop of:
component rendering → fetch → data is set to state → state update triggers a re-render → re-render triggers another fetch -> the fetch updates state -> re-render → infinite loop.
Instead, we can use a {useEffect}
hook for our GET to render once, and the empty dependency array will make sure it won't re-render.
useEffect(() => {
fetch('fetchURL')
.then(response => response.json())
.then(data => setState(data))
}, [])
POST
We can handle post requests by having a handler function receive the return data.
Here's an example of a form submitting Component:
import React, { useState } from "react";
function NewItemForm({ onAddItem }) {
const defaultFormData = {
example1: "",
example2: ""
}
const [formData, setFormData] = useState(defaultFormData)
const updateFormData = (e) => {
const { name, value } = e.target;
setFormData({ ...formData, [name]: value });
};
const handleSubmit = (e) => {
e.preventDefault();
const postConfig = {
method: "POST",
headers: {
"Content-Type": "application/json",
"Accept": "application/json"
},
body: JSON.stringify(formData),
};
fetch('fetchURL/Items', postConfig)
.then(response => response.json())
.then((newItem => {
onAddItem(newItem);
setFormData(defaultFormData);
}))
}
return (
<form onSubmit={handleSubmit} >
<input onChange={updateFormData} name="example1" value={formData.example1} />
<input onChange={updateFormData} name="example2" value={formData.example2} />
<input type="submit" value="Submit" />
</form>
);
}
export default NewItemForm;
For POST we would usually want to concatenate the new data to the existing data array.
So we need to be aware to not overwrite the existing data. Fortunately, we have the spread operator to help us out.
This is an example of how our handler handleNewItem (what onAddItem is called in the parent component) may look like:
const handleNewItem = (newItem) => {
const updatedItemList = [...itemList, newItem];
setItemList(updatedItemList)
}
By using this method, we avoid changing the state array directly (a subject worthy of it's own blog post) and update our array with the new item.
PATCH
PATCH requests are similar to POST requests.
This time we will use the .map
array method to update our array in our state. This is our way of updating a specific element in our data array.
function handleUpdateItem(newItem) {
const updatedItems = items.map(item =>
item.id === newItem.id ? newItem : item)
setItems(updatedItems)
}
const patchConfig = {
method: "PATCH",
headers: {
"Content-Type": "application/json",
"Accept": "application/json",
},
body: JSON.stringify({key: updatedValue}),
};
fetch('fetchURL/items/${item.id}', patchConfig);
.then(response => response.json())
.then(newItem => handleUpdateItem(newItem))
Delete
Deleting requires us to use the filter
array function.
If we simply let everything in except for the deleted item, we achieve our goal again without deleting from the array in state directly.
const handleDelete = (id) => {
const updateItemList = itemList.filter((item) => item.id !== id);
setItemList(updateItemList);
}
fetch(`fetchURL/items/${item.id}`, {
method: 'DELETE'
}).then(response => {
if (response.ok) {
handleDelete(item.id)
} else {
handleError({error: "Item was not deleted"})
}
})
Conclusion
In the examples above we can see simple methods for applying state, using controlled forms, and fetching in React.
Applying the right method to manipulate the data in state, is imperative.
Now go ahead and try these out, and don't forget to be CRUD-y.
Top comments (0)