I am following the simple records list tutorial for MongoDB’s for MERN stack here. I followed all the instructions and fixed up my connection and it is working. However when I test out the app and try to create a new record by clicking Create Person
, nothing happens. Also, when I refresh the create page the alert box pops up with the error saying failed to fetch.
Now, when I click on create person again after refreshing, no alert box pops up even after refreshing again. The button doesn’t navigate back to the homepage which is what I need it to do.
// /client/src/components/create.js
import React, { useState } from "react";
import { useNavigate } from "react-router";
export default function Create() {
const [form, setForm] = useState({
name: "",
position: "",
level: "",
});
const navigate = useNavigate();
// These methods will update the state properties.
function updateForm(value) {
return setForm((prev) => {
return { ...prev, ...value };
});
}
// This function will handle the submission.
async function onSubmit(e) {
e.preventDefault();
// When a post request is sent to the create url, we'll add a new record to the database.
const newPerson = { ...form };
await fetch("http://localhost:5000/record/add", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(newPerson),
})
.catch(error => {
console.log(error);
return;
});
setForm({ name: "", position: "", level: "" });
navigate("/");
}
// This following section will display the form that takes the input from the user.
return (
<div>
<h3>Create New Record</h3>
<form onSubmit={onSubmit}>
<div className="form-group">
<label htmlFor="name">Name</label>
<input
type="text"
className="form-control"
id="name"
value={form.name}
onChange={(e) => updateForm({ name: e.target.value })}
/>
</div>
<div className="form-group">
<label htmlFor="position">Position</label>
<input
type="text"
className="form-control"
id="position"
value={form.position}
onChange={(e) => updateForm({ position: e.target.value })}
/>
</div>
<div className="form-group">
<div className="form-check form-check-inline">
<input
className="form-check-input"
type="radio"
name="positionOptions"
id="positionIntern"
value="Intern"
checked={form.level === "Intern"}
onChange={(e) => updateForm({ level: e.target.value })}
/>
<label htmlFor="positionIntern" className="form-check-label">Intern</label>
</div>
<div className="form-check form-check-inline">
<input
className="form-check-input"
type="radio"
name="positionOptions"
id="positionJunior"
value="Junior"
checked={form.level === "Junior"}
onChange={(e) => updateForm({ level: e.target.value })}
/>
<label htmlFor="positionJunior" className="form-check-label">Junior</label>
</div>
<div className="form-check form-check-inline">
<input
className="form-check-input"
type="radio"
name="positionOptions"
id="positionSenior"
value="Senior"
checked={form.level === "Senior"}
onChange={(e) => updateForm({ level: e.target.value })}
/>
<label htmlFor="positionSenior" className="form-check-label">Senior</label>
</div>
</div>
<div className="form-group">
<input
type="submit"
value="Create person"
className="btn btn-primary"
/>
</div>
</form>
</div>
);
}
I am also wondering why the records don’t show up in the records list.
// /client/src/components/recordList.js
import React, { useEffect, useState } from "react";
import { Link } from "react-router-dom";
const Record = (props) => (
<tr>
<td>{props.record.name}</td>
<td>{props.record.position}</td>
<td>{props.record.level}</td>
<td>
<Link className="btn btn-link" to={`/edit/${props.record._id}`}>Edit</Link> |
<button className="btn btn-link"
onClick={() => {
props.deleteRecord(props.record._id);
}}
>
Delete
</button>
</td>
</tr>
);
export default function RecordList() {
const [records, setRecords] = useState([]);
// This method fetches the records from the database.
useEffect(() => {
async function getRecords() {
const response = await fetch(`http://localhost:5000/record/`);
if (!response.ok) {
const message = `An error occurred: ${response.statusText}`;
window.alert(message);
return;
}
const records = await response.json();
setRecords(records);
}
getRecords();
return;
}, [records.length]);
// This method will delete a record
async function deleteRecord(id) {
await fetch(`http://localhost:5000/${id}`, {
method: "DELETE"
});
const newRecords = records.filter((el) => el._id !== id);
setRecords(newRecords);
}
// This method will map out the records on the table
function recordList() {
return records.map((record) => {
return (
<Record
record={record}
deleteRecord={() => deleteRecord(record._id)}
key={record._id}
/>
);
});
}
// This following section will display the table with the records of individuals.
return (
<div>
<h3>Record List</h3>
<table className="table table-striped" style={{ marginTop: 20 }}>
<thead>
<tr>
<th>Name</th>
<th>Position</th>
<th>Level</th>
<th>Action</th>
</tr>
</thead>
<tbody>{recordList()}</tbody>
</table>
</div>
);
}
The record.js file in the server section.
const express = require("express");
// recordRoutes is an instance of the express router.
// We use it to define our routes.
// The router will be added as a middleware and will take control of requests starting with path /record.
const recordRoutes = express.Router();
// This will help us connect to the database
const dbo = require("../db/conn");
// This help convert the id from string to ObjectId for the _id.
const ObjectId = require("mongodb").ObjectId;
// This section will help you get a list of all the records.
recordRoutes.route("/record").get(function (req, res) {
let db_connect = dbo.getDb("todolist");
db_connect
.collection("records")
.find({})
.toArray(function (err, result) {
if (err) throw err;
res.json(result);
});
});
// This section will help you get a single record by id
recordRoutes.route("/record/:id").get(function (req, res) {
let db_connect = dbo.getDb("todolist");
let myquery = { _id: ObjectId(req.params.id) };
db_connect
.collection("records")
.findOne(myquery, function (err, result) {
if (err) throw err;
res.json(result);
});
});
// This section will help you create a new record.
recordRoutes.route("/record/add").post(function (req, response) {
let db_connect = dbo.getDb("todolist");
let myobj = {
name: req.body.name,
position: req.body.position,
level: req.body.level,
};
db_connect.collection("records").insertOne(myobj, function (err, res) {
if (err) throw err;
response.json(res);
});
});
// This section will help you update a record by id.
recordRoutes.route("/update/:id").post(function (req, response) {
let db_connect = dbo.getDb("todolist");
let myquery = { _id: ObjectId(req.params.id) };
let newvalues = {
$set: {
name: req.body.name,
position: req.body.position,
level: req.body.level,
},
};
db_connect
.collection("records")
.updateOne(myquery, newvalues, function (err, res) {
if (err) throw err;
console.log("1 document updated");
response.json(res);
});
});
// This section will help you delete a record
recordRoutes.route("/:id").delete((req, response) => {
let db_connect = dbo.getDb("todolist");
let myquery = { _id: ObjectId(req.params.id) };
db_connect.collection("records").deleteOne(myquery, function (err, obj) {
if (err) throw err;
console.log("1 document deleted");
response.json(obj);
});
});
module.exports = recordRoutes;
2
Answers
I figured it out. I put the fetch call in using a try and catch block like this. The database updates correctly and the button works as expected.
I suggest you check your api with a Postman API tester. Firstly check your back-end part. Is your created API working or not? If Your back-end API is working correctly then check the front-end part. It is helpful because you can understand which part of the problem.