When submitting network requests, we want to update the UI to indicate 3 different statuses:

Let’s try taking a look at the approach we’d think to attempt at the first chance

import React,{useState, useEffect} from 'react'

const [data, setData] = useState(null)
const [loading, setLoading] = useState(false)
const [error, setError] = useState(false)

const ENDPOINT = '<https://www.google.com>'

useEffect(() => {
	setLoading(true)
	async function getAPIResponse(){
			const response = await fetch(ENDPOINT)

			if(!response.ok){
				setError(true)
			}

			const responseJSON = await response.json()
			setData(responseJSON)
			setLoading(false)
		}

	getAPIResponse()
}, [])

if(loading){
	return(
		<p>......</p>
	)
	}

if(error){
	return(
		<p>error</p>
	)
	}

const ExampleComponent = () => {
	return (
			<div>
					<h1>{data?.title}</h1>
			</div>
)
}

export default ExampleComponent

Looks simple right?

Let’s talk about the foot-guns you can shoot yourself with now:

The above scenario is the level 0 of the complexities, that we are going to be diving into.

In large codebases with complex interfaces, this model kind of breaks I can easily come up with more than 5 scenarios where this model would break

If we treat modularity as the core principle on the frontend codebase, dividing our frontend codebase into reusable components might make the most sense but now what if each of those components write to the backend server, considering what we talked about, the page is our universal source for all the logic flowing down.

Now in this case passing the data down as props along with getters and setters would make most sense right?

Let’s say we can choose to abstract API fetcher functions inside a lib file and call them at the page level but at that point you are just choosing to hide the complexity not make it simple

The other contradiction which it creates is with modularity passing getter and setter state variables down your comp heirarchy as props creates more problems rather than solutions

List of frictions:

  1. Changing 5 files to change 1 logic
  2. Codebase is harder to debug with prop drillings 5 6 levels down
  3. Unknown re renders all through out our application, causing weird errors
  4. Messier file management for the engineer, which adds more to the complexity rather than simplicity, which in turn makes the codebase harder to navigate and contribute to.

This is the layer 0 of the complexity that we will be getting into if we are not using something like useSWR or react-query, as the company grows and these things starts to matter

  1. cost per API call
  2. Caching the response so that it can be reused by multiple components across the app.
  3. Revalidating the data so that it never becomes too stale.

Now this is a whole new rabbit hole we can get into, but again the effort/upside ratio and the extra management cost on our codebase is not worth it in my opinion