РЕДАКТИРОВАТЬ: Ссылка на репозиторий проекта можно найти здесь .
Я пытаюсь получить данные, когда страница моего профиля загружается в моем приложении React. У меня есть клиент, работающий на моем локальном хосте: 3000, и сервер на локальном хосте: 5000.
У меня также есть прокси в пакете. json моей клиентской папки, которая указывает на локальный хост: 5000 (предположительно) , В моем файле сервера также есть cors, и все обычные навороты, которые я использовал в прошлом.
Всякий раз, когда мой компонент монтируется, в моей консоли я получаю ошибку 404 о том, что мой запрос GET не выполнен, и он говорит, что он пытался достичь localhost: 3000 / recipes - согласно моему прокси-серверу, это неправильно, поскольку он должен делать запрос к localhost: 5000.
Однако, это становится еще сложнее, потому что, чтобы проверить это, я изменил и жестко закодировал мой маршрут к localhost: 5000, но даже это вернуло ошибку 404.
Сначала я подумал, что что-то не так с моим логином GET-запроса бэкэнда c, но дело в том, что когда я вкалываю та же функция, которая выполняет запрос get внутри componentDidUpdate (), она успешно извлекает все рецепты (это приложение для рецептов), только запускает бесконечное l oop и сходит с ума, и, очевидно, у меня этого не может быть.
Кто-нибудь знает, что здесь происходит? Почему моя функция getRecipes () (которая делает запрос get) не работает внутри componentDidMount (), получает ошибку 404, не успешно проксирует, но затем работает внутри componentDidUpdate ()? Почему бесконечный l oop?
Вот мой код внешнего интерфейса:
import React, { Component } from "react";
import {
Button,
Modal,
ModalHeader,
ModalBody,
Form,
FormGroup,
Label,
Input
} from "reactstrap";
import styles from "./RecipeList.module.css";
// import { addRecipe } from "../RecipeFunctions/RecipeFunctions";
import axios from "axios";
import RecipeItem from "../RecipeItem/RecipeItem";
import jwt_decode from "jwt-decode";
export default class RecipeList extends Component {
state = {
recipes: [],
modal: false,
email: "",
recipeName: "",
ingredients: "",
directions: "",
errors: {
msg: ""
}
};
toggle = () => {
this.setState({
modal: !this.state.modal
});
};
onChange = e => {
this.setState({
[e.target.name]: e.target.value
});
};
onSubmit = e => {
e.preventDefault();
const newRecipe = {
user_email: this.state.email,
title: this.state.recipeName,
ingredients: this.state.ingredients,
directions: this.state.directions
};
// Make Post Request w/ Axios from RecipeFunctions.js
this.addRecipe(newRecipe);
this.getRecipes();
};
getRecipes = () => {
axios.get(`/recipes/${this.state.email}`).then(res => {
this.setState({
recipes: res.data
});
});
};
addRecipe = newRecipe => {
axios.post("/recipes", newRecipe).then(response => {
console.log("Recipe added.");
console.log(this.state.email)
});
};
deleteRecipe = id => {
axios
.delete(`/recipes/${id}`)
.then(this.getRecipes())
.catch(err => console.log(err));
};
viewRecipe = id => {
axios
.post(`/viewrecipe/${id}`)
.then(this.getRecipes())
.catch(err => console.log(err));
};
closeRecipe = id => {
axios
.post(`/closerecipe/${id}`)
.then(this.getRecipes())
.catch(err => console.log(err));
};
componentDidMount() {
try {
const token = localStorage.usertoken;
const decoded = jwt_decode(token);
this.setState({
firstname: decoded.firstname,
lastname: decoded.lastname,
email: decoded.email
});
} catch {
this.setState({
errors: {
msg: "You must be logged in to see your profile."
}
});
}
this.getRecipes();
}
render() {
if (this.state.email) {
return (
<div id={styles.compWrapper} className="container">
<div>
<div id={styles.titleWrapper} className="col-sm-8 mx-auto">
<h1 className="text-center">{this.state.firstname}'s Cookbook</h1>
</div>
<div className="text-center">
<div>
<Button
id={styles.addRecipeBtn}
outline
color="secondary"
onClick={this.toggle}
size="sm"
>
Add Recipe
</Button>
<div className={styles.feedWrapper}>
<Modal
className={styles.addRecipeModal}
isOpen={this.state.modal}
toggle={this.toggle}
>
<ModalHeader toggle={this.toggle}>New Recipe</ModalHeader>
<ModalBody>
<Form onSubmit={this.onSubmit}>
<FormGroup>
<Label for="item">Recipe Name</Label>
<Input
type="text"
name="recipeName" // *must match this.state above
id="item"
placeholder="ex. Chicken Pot Pie"
onChange={this.onChange}
/>
<Label className={styles.inputLabel} for="item">
Ingredients
</Label>
<Input
type="textarea"
size="lg"
name="ingredients" // *must match this.state above
id={styles.ingredientsTextArea}
onChange={this.onChange}
/>
<Label className={styles.inputLabel} for="item">
Directions
</Label>
<Input
type="textarea"
size="lg"
name="directions" // *must match this.state above
id={styles.directionsTextArea}
onChange={this.onChange}
/>
<Button
color="dark"
style={{ marginTop: "2rem" }}
block
onClick={this.toggle}
>
Add
</Button>
</FormGroup>
</Form>
</ModalBody>
</Modal>
</div>
<div
id={styles.recipeListWrapper}
className="recipe-list-container"
>
{this.state.recipes.map(recipe => (
<RecipeItem
id={recipe._id}
title={recipe.title}
ingredients={recipe.ingredients}
directions={recipe.directions}
beingViewed={recipe.beingViewed}
viewRecipe={this.viewRecipe}
closeRecipe={this.closeRecipe}
deleteRecipe={this.deleteRecipe}
/>
))}
</div>
</div>
</div>
</div>
</div>
);
} else {
return (
<p className="text-center jumbotron mt-5">{this.state.errors.msg}</p>
);
}
}
}
А вот и мой сервер. js:
const express = require("express");
const path = require('path');
const cors = require("cors");
const bodyParser = require("body-parser");
const app = express();
const mongoose = require("mongoose");
const dotenv = require("dotenv");
const port = process.env.PORT || 5000;
app.use(bodyParser.json());
app.use(cors());
app.use(
bodyParser.urlencoded({
extended: false
})
);
dotenv.config();
const db = process.env.DB_CONNECT;
const Users = require("./routes/Users");
const Recipes = require("./routes/Recipes");
app.use("/users", Users);
app.use("/recipes", Recipes);
mongoose
.connect(db, {
useUnifiedTopology: true,
useNewUrlParser: true,
useCreateIndex: true
})
.then(() => console.log("MongoDB Connected..."))
.catch(() => console.log(err));
app.post("/viewrecipe/:id", (req, res) => {
Recipe.findOneAndUpdate({ _id: req.params.id }, { $set: { beingViewed: true } })
.then(res.send("Recipe being viewed."))
.catch(err => console.log(err));
});
app.post("/closerecipe/:id", (req, res) => {
Recipe.findOneAndUpdate({ _id: req.params.id }, { $set: { beingViewed: false } })
.then(res.send("Recipe closed."))
.catch(err => console.log(err));
});
app.get("/showrecipes", (req, res) => {
Recipe.find({}).then(recipes => res.send(recipes));
});
app.delete("/deleterecipes", (req, res) => {
Recipe.deleteMany({}).then(res.send("All recipes deleted. Database empty."));
});
// Serve static assets if in production
if(process.env.NODE_ENV === 'production') {
// Set static folder
app.use(express.static('client/build'));
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'));
});
}
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});
При необходимости , вот фактический маршрут («рецепты» - это express маршрутизатор с базой / recipes):
recipes.get("/:useremail", (req, res) => {
if (!req.params.useremail) {
res.send("You must be logged in to access recipes.");
}
Recipe.find({
user_email: req.params.useremail
})
.then(recipes => {
res.send(recipes)
.catch(err => {
res.send("error: " + err);
});
});
Любая помощь приветствуется!