Клиентский прокси-узел Node / React не работает, componentDidMount () не получает данные - PullRequest
0 голосов
/ 28 января 2020

РЕДАКТИРОВАТЬ: Ссылка на репозиторий проекта можно найти здесь .

Я пытаюсь получить данные, когда страница моего профиля загружается в моем приложении 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);
    });
});

Любая помощь приветствуется!

1 Ответ

0 голосов
/ 28 января 2020

в вашем запросе на выборку, попробуйте использовать 192.168.17.161:5000 вместо localhost: 5000

...