Lockdown (3)

Benton Westergaard
3 min readSep 27, 2021

(This is the third part in a series. Last entry here )

For a quick recap, I am building a react app which I want to lockdown using Auth. Before I get to OAuth, however, I want to make sure the app has CRUD functionality. At this point, the app has a list of items (bicycles), and a form to create new items/bicycles for the collection. Where I left off last week, the form does is not yet connected to the backend. So, let’s make the form actually do something!

Important to remember that this form gets it’s values from state. So, my first logical step is to give values to each one of the form inputs. For example, the value for the usage input will be value={this.state.usage}

<form className="bicycle-form" >
<h3>Create a new bicycle entry</h3>
<label>Usage</label>
<input type="text" name="usage"/><label>Frame Material</label> value={this.state.usage}
<input type="text" name="frame_material" value={this.state.frame_material}/>
<label>Manufacturer</label>
<input type="text" name="manufacturer" value={this.state.manufacturer}/>
<label>Speeds</label>
<input type="text" name="speeds" value={this.state.usage}/>
<input type="submit" />
</form>

This looks really redundant, however, so I’m going to restructure. Rewriting “this.state…” over and over again for each input can be avoided thusly:

render(){
const { usage, frame_material, manufacturer, speeds } = this.state
return (
<form className="bicycle-form" >
<h3>Create a new bicycle entry</h3>
<label>Usage</label>
<input type="text" name="usage" value={usage} />
<label>Frame Material</label>
<input type="text" name="frame_material" value={frame_material} />
<label>Manufacturer</label>
<input type="text" name="manufacturer" value={manufacturer}/>
<label>Speeds</label>
<input type="text" name="speeds" value={usage}/>
<input type="submit" />
</form>
)
}

Each input will also require a onChange function, so I’ll add this, too:

render(){
const { usage, frame_material, manufacturer, speeds } = this.state
return (
<form className="bicycle-form" >
<h3>Create a new bicycle entry</h3>
<label>Usage</label>
<input type="text" name="usage" value={usage} onChange={this.handleChange} />
<label>Frame Material</label>
<input type="text" name="frame_material" value={frame_material} onChange={this.handleChange}/>
<label>Manufacturer</label>
<input type="text" name="manufacturer" value={manufacturer} onChange={this.handleChange} />
<label>Speeds</label>
<input type="text" name="speeds" value={usage} onChange={this.handleChange} />
<input type="submit" />
</form>
)
}

Of course, now I need to add a function for handleChange:

handleChange = (event) => {
let { name, value } = event.target

this.setState({
[name]: value
})
}

Next step is to addd a handleSubmit function on the form, and build a function for it. It’s important to note at this stage, that what the form will be doing is to change state of bicycles, which is held in App.js (we are in BicycleForm.js). So, I also need to modify App.js to accommodate the state change from BicycleForm.js. In the function below, I am taking the current state of bicycles, and adding the new bicycle (created from the form).

(this is in the App.js file)addBicycle = (newBicycle) => {
this.setState({
bicycles: [...this.state.bicycles, newBicycle]
})
}

I also need to include addBicycle as a prop in the render method for BicycleForm. The function is not invoked because it is invoked in BicycleForm.js, not App.js:

<BicycleForm addBicycle={this.addBicycle} />

Now, back in BicycleForm.js, I call the newBicycle using props:

handleSubmit = (event) => {
event.preventDefault()
this.props.addBicycle(this.state)
}

So all together, I now have:

render(){
const { usage, frame_material, manufacturer, speeds } = this.state
return (
<form className="bicycle-form" onSubmit={this.handleSubmit}
>
<h3>Create a new bicycle entry</h3>
<label>Usage</label>
<input type="text" name="usage" value={usage} onChange={this.handleChange} />
<label>Frame Material</label>
<input type="text" name="frame_material" value={frame_material} onChange={this.handleChange}/>
<label>Manufacturer</label>
<input type="text" name="manufacturer" value={manufacturer} onChange={this.handleChange} />
<label>Speeds</label>
<input type="text" name="speeds" value={usage} onChange={this.handleChange} />
<input type="submit" />
</form>
)
}

It’s a good idea to test this in the browser using component tools, to make sure the input values are being saved in state, as intended.

Now, to make it persist.

First, I need to make a route on the backend to handle the creation of a new bicycle. So, in the bicycles_controller.rb file:

def create
@bicycle = Bicycle.create(
usage: params[:usage],
frame_material: params[:frame_material],
manufacturer: params[:manufacturer],
speeds: params[:speeds]
)
render json: @bicycle, status: :created
end

Now, to make the new bicycle persist, I just need to add a fetch to the addBicycle function within App.js:

addBicycle = (newBicycle) => {
this.setState({
bicycles: [...this.state.bicycles, newBicycle]
})
fetch(BASEURL, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(newBicycle)
})
}

Voila! Now, new bicycles added by the form will be stored in the backend.

For the next blog, I’ll cover updating and deleting bicycles, and eventually, get to Auth.

I think it’s really important to get the app functionality figured out BEFORE adding auth, because there are several things I need to do to make auth work for all CRUD functionality that are complex. Stay tuned…

github (front and backend in one repo)

--

--