Маршрут продукта не определен и не отображается на интерфейсной части ReactJS, MongoDB

#javascript #node.js #reactjs #mongodb #redux

Вопрос:

У меня возникают проблемы с отображением продукта, когда я пытаюсь ПОЛУЧИТЬ api/products/:id , мой браузер возвращается localhost:3000/produit/undefined , и запрос не удался с кодом состояния 500

репо ссылок : https://github.com/Kwonsongji/mern-stack-calone-shop Вот моя обратная часть : Модель : Product.js

 const mongoose = require('mongoose');

const productSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true
  },
  image: {
    type: String,
    required: true
  },
  price: {
    type: Number,
    required: true
  },
  material: {
    type: String,
    required: true
  },
 
  countInStock: {
    type: Number,
    required: true
  },
}, {
  timestamps: true
})
const Product = mongoose.model('Product', productSchema);

module.exports = Product;
 

Контроллер : productCtrl.js

 const db = require('../config/db');
const Product = require('../models/Product');
const datas = require('../data/datas');


const productCtrl = {
  sendDatasProductToMoongoose: async (req, res) => {
    try {
      //await db.products.dropIndexes({})
      await Product.deleteMany({})
                    //.remove({});  
      const createdProducts = await Product.insertMany(datas.products);
      console.log('Data Import Sucess createdProducts',createdProducts);
      res.send({ createdProducts});
    } catch (error) {
      res.status(500).send(error.message)
    }
  },  

  getAllProducts: async (req, res) => {
    try {
      console.log("req :", req.body);
      // Product.find({})
      const products = await Product.find()
        .then((Document) => {
          console.log("Document: ", Document);
           console.log("Req.params: ", req.params);
           if (!Document) {
            return res
                    .status(404)
                    .json({ message: "This ressource doesn't exist " });
          } 
          res.status(200).json(datas.products);
         })
        .catch((error) => {
          console.log(error);
          res.status(500).json(error)
        });
  } catch (error) {
    console.error(error);
    res.status(500).json({ message: "Server Error" });
    }
  },
    getProductById: async (req, res) => {
      try {
 /*        const product = await Product.findOne(_id)  */
        const product = await Product.findById(req.params.id)  
        /*  .then((Document) => {
          if (!Document) {
            return res
              .status(404)
              .json({ message: "This document doesn't exist" });
          }
          res.status(200).json(Document);
        })
        .catch((error) => {
          res.status(500).json(error);
        });  */
       res.send(product); // returne moi les données en json
    } catch (error) {
      console.error(error);
      res.status(500).json({ message: "Server Error" });
    }
  },
 
};

module.exports = productCtrl;
 

Router : product.js

 const productCtrl = require('../controllers/productCtrl');
const router = express.Router();

router.get('/seed', productCtrl.sendDatasProductToMoongoose )
router.get('/', productCtrl.getAllProducts);
router.get('/:id', productCtrl.getProductById);

module.exports = router;
 

Server : server.js

 const express = require("express");
const cors = require("cors");
// require connexion db and run it 
const connectDB = require("./config/db");
const app = express();

connectDB();

app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cors());

app.use("/api/products",require("./routes/product.js"));
app.use("/api/users",require("./routes/user.js"))

const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`Server running on ${PORT}`));
 

Frontend :
productActions :

 import * as actionTypes from '../constants/productConstants';
import axios from 'axios';

export const getProducts = () => async (dispatch) => {
  try {
    dispatch({ type: actionTypes.GET_PRODUCTS_REQUEST });

    const { data } = await axios.get(`/api/products`);

    dispatch({
      type: actionTypes.GET_PRODUCTS_SUCESS,
      payload: data
    })
  } catch (error) {
    dispatch({
      type: actionTypes.GET_PRODUCTS_FAIL,
      payload: error.response amp;amp; error.response.message
        ? error.response.data.message
        : error.message
    });

  }
};


export const getProductDetails = (id) => async (dispatch) => {
  try {
    dispatch({ type: actionTypes.GET_PRODUCT_DETAILS_REQUEST });

    const { data } = await axios.get(`/api/products/${id}`);

    dispatch({
      type: actionTypes.GET_PRODUCT_DETAILS_SUCESS,
      payload: data
    })
  } catch (error) {
    dispatch({
      type: actionTypes.GET_PRODUCT_DETAILS_FAIL,
      payload: error.response amp;amp; error.response.message
        ? error.response.data.message
        : error.message
    });

  }
};
export const removeProductDetails = () => (dispatch) => {
  dispatch({ type: actionTypes.GET_PRODUCT_DETAILS_RESET });
};
 

productReducer.js:

 import * as actionTypes from '../constants/productConstants';

const initialStateForGetProducts = {
  products: []
};
export const getProductsReducer = (state = initialStateForGetProducts, action) => {
  switch (action.type) {
    case actionTypes.GET_PRODUCTS_REQUEST:
      return {
        loading: true,
        products:[] 
      }
    case actionTypes.GET_PRODUCTS_SUCESS:
      return {
        loading: false,
        products: action.payload
      }
    case actionTypes.GET_PRODUCTS_FAIL:
      return {
        loading: false,
        error: action.payload //on veut afficher l'erreur
      } 
    default:
      return state;
  }
}

const initialStateForGetOneProduct = {
  product: {}
}
export const getProductDetailsReducer = (state = initialStateForGetOneProduct, action) => {
  switch (action.type) {
    case actionTypes.GET_PRODUCT_DETAILS_REQUEST:
      return {
        loading: true,
      }
    case actionTypes.GET_PRODUCT_DETAILS_SUCESS:
      return {
        loading: false,
        product: action.payload
      }
      case actionTypes.GET_PRODUCT_DETAILS_FAIL:
      return {
        loading: false,
        error: action.payload
      }
    case actionTypes.GET_PRODUCT_DETAILS_RESET:
      return {
      product: {}
      } 
    default:
      return state;
  }
}
 

ProductScreen.js

 /* eslint-disable react/prop-types */
import React from 'react';
import './style.scss';
//import moonPendant from '../../assets/fonts/moon-pendant.png';
import { useState, useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';

// Actions
import { getProductDetails } from '../../../redux/actions/productActions';
import { addToCart } from '../../../redux/actions/cartActions'; 

const ProductScreen = ( {match, history}) => {
   const [qty, setQty] = useState(1);
  const dispatch = useDispatch();
  
   const productDetails = useSelector(state => state.getProductDetails);
   const { loading, error, product } = productDetails;

   useEffect(() => {
     if (product amp;amp; match.params.id !== product._id) {
       dispatch(getProductDetails(match.params.id));
     }
   }, [dispatch, product, match]); 
  
   
  const addToCartHandler = () => {
    dispatch(addToCart(product._id, qty));
    history.push("/panier");
  }
  return (
    <div className="productScreen">
      { loading ? <h2>Loading...</h2>
        : error ? <h2>{error}</h2>
          : (
            <>
              
      <div className="productScreen__left">
        <div className="productScreen__left__image">
 {/*                   <img src={moonPendant} alt={product.name} />  */}
                  <img src={product.image} alt={product.name} /> 
        </div>
        <div className="productScreen__left__info">
                  <p className="productScreen__left__name"> {product.name}</p>
                  <p className="productScreen__left__price"> {product.price}</p>
                  <p className="productScreen__left__material"> {product.material}</p>
        </div>
      </div>
      <div className="productScreen__right">
        <div className="productScreen__right__info">
          <p className="productScreen__right__price">
            Prix: <span> {product.price} euros </span>
          </p>
          <p className="productScreen__right__status">
                    Statut:
                    <span>
                      {product.countInStock > 0 ? "En Stock" : "En Rupture de Stock"}
                    </span>
          </p>
          <p className="productScreen__right__qty">
            Quantité:
                    <select value={qty} /* lorsqu'on slct le nbre voulu */
                      onChange={(e) => setQty(e.target.value)}>
                {[...Array(product.countInStock).keys()].map((x) => (
                  <option
                    key={x 1}
                    value={x 1}
                  >
                    {x 1}
                  </option> //on utilise l'instance array pour créer un tableau de liste
                ))}
            </select>
          </p>
          <p>
            <button
              type="button"
              onClick={ addToCartHandler} 
              className="productScreen__right__add"           
              > Ajouter
            </button>
          </p>
        </div>
        
      </div>
            </> 
      )}
            
      
    </div>
  )
}

export default ProductScreen;

 

репо ссылок : https://github.com/Kwonsongji/mern-stack-calone-shop

Комментарии:

1. Можете ли вы показать свой файл маршрутов в интерфейсе?

2. const { data } = await axios.get( /api/продукты/${id} ); идентификатор может быть здесь не определен, проверьте перед отправкой запроса

3. Если он там не определен, проверьте dispatch(getProductDetails(match.params.id)); match.params.id не определено

4. Нам нужно только увидеть, как вы формируете свои маршруты в пользовательском интерфейсе и как это ProductScreen позволяет получить доступ к параметрам маршрута. Остальное в значительной степени просто шум на данный момент. Пожалуйста, обновите вопрос, чтобы показать, как ProductScreen визуализируется и, возможно, получает реквизиты маршрута. Ваше репо на github также кажется очень пустым.

5. @Prana @DrewRiese вот мой маршрут с фронтенда : <Route exact path="/produit/:id" component={ProductScreen}></Route>