Skip to main content

MERN Stack

Lesson Objectives#

  1. Describe the elements of the MERN stack
  2. Set up static files
  3. Set up React using Create React App
  4. Get Data from our holidays_api app
  5. Do rest of CRUD

Describe the elements of the MERN stack#

MERN stack is just a collection of tech that work well together

  • Mongo
  • Express
  • React
  • Node.js

We're going to have two apps: One will be our create-react-app that will handle the UX/UI

The other is our backend express API.

It is increasingly common to have a separate back end that just handles data: Desktop and mobile apps are different apps for a user to use, but it makes sense they'd share the backend/data rather than building out that portion twice.

We're going to make a top level folder that will hold both of our apps

Create React App#

  1. cd holidays_front_end
  2. npm install
  3. npm start

What we're building

Get Data from Our API#

First, we'll need to store our data in the state of our App.

import { useState } from "react";
const App = () => {  const [holidays, setHoliday] = useState([]);
  return (    <div className="container">      <h1>Holidays! Celebrate!</h1>    </div>  );};
export default App;

We can use fetch to make database calls for us

fetch("/holidays")  .then(    (data) => data.json(),    (err) => console.log(err)  )  .then(    (parsedData) => console.log(parsedData),    (err) => console.log(err)  );

We will likely receive a CORS ERROR

For safety reasons, requests with different origins are blocked by default.

We'll have to move over to our backend and add an npm package called cors

-npm install cors

  • in server.js, with your other dependencies
const cors = require("cors");
  • further down, with your other middleware

Note: we only need localhost for this build, but to give you an example of how to limit CORS to a white list for your project (ie your localhost and then your api on heroku)

server.js (express backend)

const whitelist = [  "http://localhost:3000",  "https://fathomless-sierra-68956.herokuapp.com",];const corsOptions = {  origin: (origin, callback) => {    if (whitelist.indexOf(origin) !== -1) {      callback(null, true);    } else {      callback(new Error("Not allowed by CORS"));    }  },};
// all routes are now exposed, // sometimes you just want to limit access // (ie OMDB - it's ok for anyone to see the movies, // but you don't want just anyone updating the movies)app.use(cors(corsOptions)); 

Now in your console you should be able to see your holiday coming back from your express backend api!

Show A list of Holidays#

Right now we're just calling this fetch on loading of this react app. But we're going to want to be able to call this functionality again and again.

Inside the class App, let's put this code inside a useEffect. We'll also set up state to hold our array of holidays

import { useEffect, useState } from "react";
const App = () => {  const [holidays, setHolidays] = useState([]);    useEffect(() => {    fetch("/holidays")      .then(        (data) => data.json(),        (err) => console.log(err)      )      .then(        (parsedData) => setHolidays(parsedData),        (err) => console.log(err)      );  }, []);
  return (    <div className="container">      <h1>Holidays! Celebrate!</h1>    </div>  );};

When to call useEffect#

We want to call useEffect when we render the app. If we put it in the render function, we'll create an infinite loop. If we call it in the constructor it might be alright. Since JS is asynchronous sometimes that fetch request will complete at the right time, sometimes it won't.

We need a more surefire way to call this function at the right time. React has some lifecycle methods for exactly this purpose. We may want to run things when a component is mounted on the DOM, when a component is unmounted, when it is updated and more. We will use useEffect(() => {...}, []) for our purpose

lifecycle flow chart

We should still see our holiday(s) from our express API console logging.

Now we want to set that data in state

Finally, we want to render it:

<h1>Holidays! Celebrate!</h1><table>  <tbody>    {holidays.map((holiday) => {      return (        <tr key={holiday._id}>          <td> {holiday.name}</td>        </tr>      );    })}  </tbody></table>

Full Code: App.js

import { useEffect, useState } from "react";
const App = () => {  const [holidays, setHolidays] = useState([]);
  useEffect(() => {    fetch("/holidays")      .then(        (data) => data.json(),        (err) => console.log(err)      )      .then(        (parsedData) => setHolidays(parsedData),        (err) => console.log(err)      );  }, []);
  return (    <div className="container">      <h1>Holidays! Celebrate!</h1>      <table>        <tbody>          {holidays.map((holiday) => {            return (              <tr key={holiday._id}>                <td> {holiday.name}</td>              </tr>            );          })}        </tbody>      </table>    </div>  );};