No classes until 12/1! Good luck on semi-finals and happy Thanksgiving!!
We've worked with Express/Firebase on the backend and React on the frontend. So far, we've been learning about them separately. How can we bring both ends together to make one working product?
"data is the new oil 🤑"
Data fetching is getting information (data) from an outside source (e.g. REST API)
The frontend wants to fetch data from the backend.
Frontend tells Backend what it wants. Backend sends the appropriate data to Frontend. Frontend displays the data to the user!
In Trends, our React website will be fetching data from our Express server.
So how do we fetch data with our React frontend?
Two important things to note:
fetchthat you can use to call API endpoints. Libraries such as
axiosprovide similar functionality.
useEffectReact hook allows you to trigger side effects, such as fetching data!
We want to keep track of our data in our component state, and use hooks like
fetch the data and update the state accordingly!
Consider this snippet of code:
Here are the important parts:
- We have
datain our component state. Later, we call
setDataon what the backend sends to us.
- We declare a type definition for the
useStatecall so that TS knows the type of data we're working with. (It can't infer type from an empty array!)
useEffecthook is used to subscribe to new data.
fetch(...)is called on an API link, followed by
.then(...)calls that format the response into json and then
setDatato the response. The
.then()calls exist because
Promise(this is explained below)
Let's take a deeper look at
"stop trying to make fetch happen 👧"
fetch(resource, [init]) is a native browser function for making web requests.
Its params are:
resource: URL of the site you are fetching from
init: optional object containing any custom settings you want to apply to the request.
- For more on the init object, refer to this link!
IMPORTANT: fetch() returns a PROMISE!
Operations like web requests don't complete instantly! You want to do other stuff while the operation is still going on.
Promises represent the eventual completion (or failure) of an async operation.
Promises are in one of three possible states:
pending: initial state; neither fulfilled nor rejected
fulfilled: operation completed successfully
rejected: operation failed
.then() is a function on Promises that return a promise.
Let's break this down!
pis a Promise.
onFulfilledis the callback function that is run when
onRejected(OPTIONAL) is the callback for when
Let's talk about types!
p in this case might be
fetch(), which returns the
Promise<Response>. If so, then
value would have the type
Then, if the fulfillment function (which takes in
value) returns type
string, then the entire expression would be type
If you've taken CS 3110 or done some functional programming outside of this
class/category theory, this might make you think of
Monads/Applicatives/Functors. The specified behavior for
Promises in JS/TS
don't exactly follow the laws of what was just listed, but for learning purposes
it may be helpful to roughly compare the
then function to
If you're interested, take a look at this snippet and notice how the types behave:
.catch() is a function on Promises that catches a rejection.
For example, you might want to
onRejected takes a parameter of type
any, since we don't know the
type of the error we will get.
fetch() returns a
Promise that resolves to a
Consider this snippet, similar to one shown above:
Here we are getting the response from an endpoint and then calling
on the response and then calling
setData on the result of
If a promise gets rejected anywhere along this chain, we will log the error in our console.
If you have too many
.then() calls within each other, you might build a
PYRAMID OF DOOM ☠.
async keyword to a function designates that function as an
async functions we can use await to designate which lines need to
be “awaited” upon to resolve
Let's say you are at a store and you want to know whether the store has something in stock. So you ask an employee named Joe and he promises you that he'll be back with the results.
You are now waiting for Joe to come back. The Promise will be pending for as long as Joe is gone.
Let's say Joe comes back with the results. Now you know whether the store is in stock or not. Now the Promise is fulfilled.
Let's say Joe doesn't come back with the results. Unfortunately an anvil fell on him or something. Now you know that Joe will not come back with the result. Now the Promise is rejected.
What if I don't like
Axios is an npm package that can give you a better experience fetching data.
It has methods like:
axios.post(url[, data[, config]])
axios.put(url[, data[, config]])
Axios also returns a promise and can be resolved with
Here's an example:
In Typescript you can provide type definitions for the response you'll get from
a request, similar to what we do in
useState<type>. If you don't specify,
you'll get the
When you are testing your backend and frontend together on localhost, you will come across some sort of CORS policy error when you try to call the backend from the frontend.
One way to get around this is to add this line to your frontend's
8080 is the the port of your backend (change it accordingly).
After adding the proxy config, remove the base URL from your requests:
You keep track of your data in component state. Your app displays whatever data you have.
You update your data by calling an endpoint within
useEffect and setting your
data to the response that you get back.
You can call endpoints using
axios and handle the responses