People Build, Show, Edit and Delete
Links to Show Page
We want generate links to each persons show page so let's do the following in Index.js
import { useState } from "react"
import { Link } from "react-router-dom"
function Index(props) {
// state to hold formData
const [newForm, setNewForm] = useState({
name: "",
image: "",
title: "",
})
// handleChange function for form
const handleChange = event => {
setNewForm({ ...newForm, [event.target.name]: event.target.value })
}
// handle submit function for form
const handleSubmit = event => {
event.preventDefault()
props.createPeople(newForm)
setNewForm({
name: "",
image: "",
title: "",
})
}
// loaded function
const loaded = () => {
return props.people.map(person => (
<div key={person._id} className="person">
<Link to={`/people/${person._id}`}>
<h1>{person.name}</h1>
</Link>
<img src={person.image} alt={person.name} />
<h3>{person.title}</h3>
</div>
))
}
const loading = () => {
return <h1>Loading...</h1>
}
return (
<section>
<form onSubmit={handleSubmit}>
<input
type="text"
value={newForm.name}
name="name"
placeholder="name"
onChange={handleChange}
/>
<input
type="text"
value={newForm.image}
name="image"
placeholder="image URL"
onChange={handleChange}
/>
<input
type="text"
value={newForm.title}
name="title"
placeholder="title"
onChange={handleChange}
/>
<input type="submit" value="Create Person" />
</form>
{props.people ? loaded() : loading()}
</section>
)
}
export default Index
The Show Page
Let's pass the people data to the Show page via props and make a update and delete function for the show page, head over to Main.js
import { useEffect, useState } from "react"
import { Route, Switch } from "react-router-dom"
import Index from "../pages/Index"
import Show from "../pages/Show"
function Main(props) {
const [people, setPeople] = useState(null)
const URL = "http://localhost:4000/people/"
const getPeople = async () => {
const response = await fetch(URL)
const data = await response.json()
setPeople(data)
}
const createPeople = async person => {
// make post request to create people
await fetch(URL, {
method: "post",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(person),
})
// update list of people
getPeople()
}
const updatePeople = async (person, id) => {
// make put request to create people
await fetch(URL + id, {
method: "put",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(person),
})
// update list of people
getPeople()
}
const deletePeople = async id => {
// make delete request to create people
await fetch(URL + id, {
method: "delete",
})
// update list of people
getPeople()
}
useEffect(() => getPeople(), [])
return (
<main>
<Switch>
<Route exact path="/">
<Index people={people} createPeople={createPeople} />
</Route>
<Route
path="/people/:id"
render={rp => (
<Show
people={people}
updatePeople={updatePeople}
deletePeople={deletePeople}
{...rp}
/>
)}
/>
</Switch>
</main>
)
}
export default Main
Let's grab the selected person from the people array in props and display them.
Show.js
function Show(props) {
const id = props.match.params.id
const people = props.people
const person = people.find(p => p._id === id)
return (
<div className="person">
<h1>{person.name}</h1>
<h2>{person.title}</h2>
<img src={person.image} alt={person.name} />
</div>
)
}
export default Show
Updating a Person
On the show page let's add
- state for a form
- handleChange and handleSubmit function
- a form in the JSX below the person
import { useState } from "react"
function Show(props) {
const id = props.match.params.id
const people = props.people
const person = people.find(p => p._id === id)
// state for form
const [editForm, setEditForm] = useState(person)
// handleChange function for form
const handleChange = event => {
setEditForm({ ...editForm, [event.target.name]: event.target.value })
}
// handlesubmit for form
const handleSubmit = event => {
event.preventDefault()
props.updatePeople(editForm, person._id)
// redirect people back to index
props.history.push("/")
}
return (
<div className="person">
<h1>{person.name}</h1>
<h2>{person.title}</h2>
<img src={person.image} alt={person.name} />
<form onSubmit={handleSubmit}>
<input
type="text"
value={editForm.name}
name="name"
placeholder="name"
onChange={handleChange}
/>
<input
type="text"
value={editForm.image}
name="image"
placeholder="image URL"
onChange={handleChange}
/>
<input
type="text"
value={editForm.title}
name="title"
placeholder="title"
onChange={handleChange}
/>
<input type="submit" value="Update Person" />
</form>
</div>
)
}
export default Show
Deleting a Person
Last Stop is adding a button on the show page to delete a user!
import { useState } from "react"
function Show(props) {
const id = props.match.params.id
const people = props.people
const person = people.find(p => p._id === id)
const [editForm, setEditForm] = useState(person)
// handleChange function for form
const handleChange = event => {
setEditForm({ ...editForm, [event.target.name]: event.target.value })
}
const handleSubmit = event => {
event.preventDefault()
props.updatePeople(editForm)
props.history.push("/")
}
const removePerson = () => {
props.deletePeople(person._id)
props.history.push("/")
}
return (
<div className="person">
<h1>{person.name}</h1>
<h2>{person.title}</h2>
<img src={person.image} alt={person.name} />
<button id="delete" onClick={removePerson}>
DELETE
</button>
<form onSubmit={handleSubmit}>
<input
type="text"
value={editForm.name}
name="name"
placeholder="name"
onChange={handleChange}
/>
<input
type="text"
value={editForm.image}
name="image"
placeholder="image URL"
onChange={handleChange}
/>
<input
type="text"
value={editForm.title}
name="title"
placeholder="title"
onChange={handleChange}
/>
<input type="submit" value="Update Person" />
</form>
</div>
)
}
export default Show
Some Final Styling
A few more changes to our styles.scss
// --------------------------
// VARIABLES
// --------------------------
$maincolor: black;
$contrastcolor: white;
@mixin white-text-black-bg {
color: $contrastcolor;
background-color: $maincolor;
}
@mixin black-test-white-bg {
color: $maincolor;
background-color: $contrastcolor;
}
// --------------------------
// Header
// --------------------------
nav {
@include white-text-black-bg;
display: flex;
justify-content: flex-start;
a {
@include white-text-black-bg;
div {
margin: 10px;
font-size: large;
}
}
}
// --------------------------
// Form
// --------------------------
section,
div {
form {
input {
@include white-text-black-bg;
padding: 10px;
font-size: 1.1em;
margin: 10px;
&[type="submit"]:hover {
@include black-test-white-bg;
}
}
}
}
// --------------------------
// button
// --------------------------
button#delete {
@include white-text-black-bg;
display: block;
margin: auto;
font-size: 1.3em;
padding: 10px;
}
// --------------------------
// images
// --------------------------
img {
width: 300px;
height: 300px;
border-radius: 90px;
object-fit: cover;
}
Deploy
- add a netlify.toml with the following
[[redirects]]
from = "/*"
to = "/index.html"
NOTE, if you wanted to deploy to Version you'd include a vercel.json with the follow
{
"version": 2,
"routes": [
{ "handle": "filesystem" },
{ "src": "/.*", "dest": "/index.html" }
]
}
- push frontend repo to github
- connect to netlify
- done
Finished Backend App Example Finished Frontend App Example
Lab - Complete Your Cheese App
Complete your cheese app using the steps of todays lessons adding the following:
- the ability see an individual cheese
- the ability edit a cheese
- the ability to delete a cheese