Lockdown! (2)

Benton Westergaard
5 min readSep 15, 2021

I am continuing on from my blog last week…

This series will cover a rails/react app that uses OAuth for user authentication.

To summarize progress up to this point: we have a rails backend seeded with four bicycles, and a show method to pull up the items on the rails server; the front end has a class component main page (App.js), and two functional components for BicycleItem.js and BicycleContainer.js. I stopped last week just before importing these components into App.js. Now, to continue…

(don’t forget to ensure that both the rails and react servers are running)

The first thing I want to do is add a life-cycle component to App.js to help import data from the backend. The life-cycle method only runs once:

componentDidMount(){
fetch(BASEURL)
.then(response => response.json())
.then(console.log())
}

I’m using console.log before doing anything else to make sure I am receiving the correct information from my backend. Sure enough, upon refreshing the page for my React server, I see an array of bicycles in my console.

Since my console.log is showing the right information, I’m going to replace it with a function to setState, specifying my key and variable pair:

componentDidMount(){
fetch(BASEURL)
.then(response => response.json())
.then(bicycles => this.setState({bicycles: bicycles}))
}

Since Javascript allows me to use a shorthand when the key:variable pair is the same, I can clean this up:

componentDidMount(){
fetch(BASEURL)
.then(response => response.json())
.then(bicycles => this.setState({bicycles}))
}

Continuing to check my progress and prevent typos, mistakes, etc., it’s a good idea to make sure that the bicycles from my backend are now stored instate. Fortunately, the components tab on my browser shows the bicycle array in state. Onward.

Now, I’m going to create a separate function for my fetch, and then call that in componentDidMount:

componentDidMount(){
this.getBicycles()
}
getBicycles = () => {
fetch(BASEURL)
.then(response => response.json())
.then(bicycles => this.setState({bicycles}))
}

Now that my bicycles are in State, I need to make them show up on the page. First step is to import my BicycleContainer.js and BicycleItem.js components to App.js:

import BicycleContainer from './components/BicycleContainer';
import BicycleItem from './components/BicycleContainer';

Now, down in my render, where the state of bicycles is being passed down as a prop:

<BicycleContainer bicycles={this.state.bicycles} />

Now, in my BicycleContainer.js component, I need to bring in the bicycles from BicycleItem.js. Since this is a functional component, I can create a function using prop notation:

const showBicycles = () => {
}

I want this function to map the array of bicycles and show each item, and spread out the bicycle object:

const showBicycles = () => {
return bicycles.map(bicycle => <BicycleItem key={bicycle.id} {...bicycle} />)
}

Now, down in my return, I just call (and invoke) the showBicycles function:

return(
<ul>
{showBicycles()}
</ul>
)

The bicycle items are now appearing in my browser (although no bicycle information shows yet). Now, to show the details for each item, I go to the BicycleItem.js component, continuing to destructure:

export default function BicycleItem({usage, frame_material, manufacturer, speeds}) {
return(
<li>
<h4>{usage}</h4>
<h4>{frame_material}</h4>
<h4>{manufacturer}</h4>
<h4>{speeds}</h4>
</li>
)
}

The bicycle info is now shown as a (very ugly) list in my browser! Before proceeding further, I need to add some styling so this info is more readable. To create a reference point for my App.css file, I add a classname to my <li>:

<li className="bicycle-item"

Back in my BicycleContainer.js component, I also add a className to the <ul>

<ul className="bicycle-list>

Now, in my CSS, I add some styling to make the cards appear more logically on the screen (I’m not going to go into the reasoning behind this, since CSS is not the focus of this series):

.bicycle-list {
display: flex;
flex-flow: row wrap;
list-style-type: none;
justify-content: space-between;
width: 90%
}
.bicycle-item {
width: 200px;
height: 180px;
box-shadow: -10px 20px 20px -10px rgb(67, 109, 3);
text-align: center;
}

Now, to start giving the page some functionality. Ultimately, I want this app to have full CRUD functionality (create, read, update, delete/destroy).

First, I want to add a BicycleForm.js component to my components folder. This will affect state, so I’m going to make it a Class component. Then, I add a form to the return, labeling the fields of the existing seed attributes:

import React, { Component } from 'react';export default class BicycleForm extends Component{
render(){
return (
<form>
<h3>Create a new bicycle entry</h3>
<label>Usage</label>
<input type="text" name="usage"/>
<label>Frame Material</label>
<input type="text" name="frame-material"/>
<label>Manufacturer</label>
<input type="text" name="manufacturer"/
<label>Speeds</label>
<input type="text" name="speeds"/>
<input type="submit" />
</form>
)
}
}

A controlled form needs to get it’s values from state, so I’ll set state up top:

state = {
usage: "",
frame_material: "",
manufacturer: "",
speeds: ""
}

Since I’ll want to clear the form later, I’ll create a const for initial state, and refer to it when I initially setState. This way, I won’t have to reset the code directly above this paragraph.

const initialState = {
usage: "",
frame_material: "",
manufacturer: "",
speeds: ""
}
class BicycleForm extends Component { state = initialState...

Now, to make the form show up on my page. First, I need to import the component into App.js:

import BicycleForm from './components/BicycleForm';

and add it to my render above BicycleContainer:

render(){
return (
<div className="App">
<h1>Bicycle App</h1>
<BicycleForm />
<BicycleContainer bicycles={this.state.bicycles} />
</div>
);
}

The form is now appearing at the top of my browser, although it looks so awkward, I need to add some basic styling before doing anything else. First, add a className to the form so I can reference it in my CSS. I’m also going to tidy up the CSS again so that everything looks a little cleaner. Again, I’m not going to go into CSS details: there are plenty of better resources on the internet on CSS, and it isn’t really the point of this blog.

body {
background-color: rgb(255, 254, 248);
}
.App {
text-align: center;
}
.bicycle-form {
display: flex;
flex-direction: column;
width: 300px;
height: 250px;
margin: auto;
justify-content: space-evenly;
background-color: rgb(189, 243, 247);
box-shadow: 10px 20px 20px -10px rgb(67, 109, 3);
padding: 20px;
border-radius: 20px;
margin-bottom: 20px;
}
.bicycle-list {
display: flex;
flex-flow: row wrap;
list-style-type: none;
justify-content: space-between;
width: 90%;
margin: 0 auto;
padding-inline-start: 0;
}
.bicycle-item {
width: 200px;
height: 180px;
box-shadow: -10px 20px 20px -10px rgb(67, 109, 3);
text-align: center;
}

Screen grab of the browser as it stands after making changes (yes, the color contrast doesn’t look great, but it shows the form distinct from the bicycle list).

For the next blog, I’ll make the form work, and continue building CRUD functionality.

github

--

--