What is the reason why I always get the same object, although I change the Id in the link

I have applied several methods to get a different object from my server. I am using React and Node JS

This is my HomeScreen. This is ok. I get everything I need.

import React,{useState,useReducer,useEffect} from 'react';
import {Link } from 'react-router-dom';
import axios from 'axios';
import logger from 'use-reducer-logger';

const reducer = (state,action) => {
   switch(action.type){
        case  'FETCH_REQUEST':
           return {...state,loading: true};
           case  'FETCH_SUCCESS':
            return {...state,products: action.payload,loading:false};
            case 'FETCH_FAIL':
               return {...state,loading:false,error: action.payload};
              default:
               return state;
            }
};
function HomeScreen(){
   const [{loading, error, products},dispatch] = useReducer(logger(reducer),{
      products: [],
      loading: true,
      error: '',
     }); 
    
   useEffect(()=>{
        const fetchData = async()=>{
         dispatch({type: 'FETCH_REQUEST'});
         try{
            const result = await axios.get('/api/products'); 
            dispatch({type: 'FETCH_SUCCESS',payload:result.data})
            
         }catch(err){
             dispatch({type: 'FETCH_FAIL', payload: err.message});
         }
         const result = await axios.get('/api/products');
         
      };
        fetchData();
   },[]);
      return (
         
         <body>
              <nav>
                   <div className="menu-background">
                            {/*<p className="menu" >Amazonas</p>*/}
                            <Link to="/" className="menu" >amazonas</Link>

                  </div>
                  <div className="logo-background">
                            <p className="logo">Menu</p>
                 </div>
                
              </nav>
              
             <ul className="products">
          {
             products.map(product=>
             <li>
                <div className="product">
           <Link to={`/product/${product._id}`}>
           <img className="image" src={product.image} alt={product.name} ></img>
          </Link>

          <Link to={`/product/${product._id}`}>{product.name}</Link>
          
          <div className="rating">{product.rating}</div>
          <div className="price">{product.price}</div>
  </div>
</li>        
)
}
</ul>

    </body>
    
      )          
           }
export default HomeScreen;

Then, I have my ProductScree. This is failing. I always get the first object from my collection of objects. Every object in my collection has a different id.

import {Link} from 'react-router-dom';
import axios from 'axios';
import React,{useState,useEffect,useReducer} from 'react';
import {useParams} from 'react-router-dom';
import logger from 'use-reducer-logger';

const reducer = (state,action) => {
      switch(action.type){
           case  'FETCH_REQUEST':
              return {...state,loading: true};
              case  'FETCH_SUCCESS':
               return {...state,product: action.payload,loading:false};
               case 'FETCH_FAIL':
                  return {...state,loading:false,error: action.payload};
                 default:
                  return state;
               }
   };

   
 
function ProductScreen(props){
            
      const params = useParams();
      const {_id} = params; 
      

      const [{loading, error, product},dispatch] = useReducer(logger(reducer),{
            product: [],
            loading: true,
            error: '',
           }); 
          
         useEffect(()=>{
              const fetchData = async()=>{
               dispatch({type: 'FETCH_REQUEST'});
               try{
                  const result = await axios.get(`/api/products/${_id}`); 
                  dispatch({type: 'FETCH_SUCCESS',payload:result.data})
                  
               }catch(err){
                   dispatch({type: 'FETCH_FAIL', payload: err.message});
               }
                              
            };
              fetchData();
         },[_id]);
            
      return(
               <div>
                     {product.name}
               </div>
               
        )
  }

export default ProductScreen;

This is my server

import express from 'express';
import data from './data.js';

const app = express();

app.get('/api/products',(req,res)=>{
    res.send(data.products);
});

app.get('/api/products/:_id',(req,res)=>{
    const product = data.products.find((x)=>x.id===req.params.id);
    if(product){
        res.send(product);
    }else{
        res.status(404).send({message: 'Product Is Not Found'});
    }
});

const port = process.env.PORT || 5000;
app.listen(port, () => {
    console.log(`serve at http://localhost:${port}`);
})

And this is my data:

export default {
    /*image: '/images/T-Shirt.jpg',*/
    products: [
        {
        _id:1,
        name: 'T-Shirt-Hurley',
        rating: 4.8,
        image: '/images/T-Shirt.jpg',
        price: '$20'
        },
        {
        _id:2,
        name: 'Jean-Levi',
        rating: 4.2,
        image: '/images/Jean.jpg',
        price: '$30'
        },
        {
        _id:3,   
        name: 'Jacket-Quicksilver',
        rating: 4.5,
        image: '/images/Jacket.jpg',
        price: '$35'
        },
        {
        _id:4,
        name: 'T-Shirt-Adidas',
        rating: 4.8,
        image: '/images/T-Shirt-2.jpg',
        price: '$20'
        },
        {
        _id:5,
        name: 'Jean-Wrangler',
        rating: 4.2,
        image: '/images/Jean-2.jpg',
        price: '$30'
        },
        {
        _id:6,
        name: 'Jacket-Champion',
        rating: 4.5,
        image: '/images/Jacket-2.jpg',
        price: '$35'
         }

        ]
      }

it seems you are using this to determine the value of _id, does the value of params change?

and then, here

isn’t the parameter _id and not id?

Thanks for your fast response!

“it seems you are using this to determine the value of _id , does the value of params change?”

Yes, you are right. it changes when I click on a new product. But, the backend continues sending me the same object. That is why I am perplexed.

isn’t the parameter _id and not id ?

I have tried both ways and I get the same result.

With _id:

Result:

with id:

Result:

This is the way it works:

Result:

it brings me everything I need of the first object of my data.js, but when I request another object, I keep getting the info from the first object.

are you sure you are using a different url?

1 Like

What do you mean?

I have used these 6. Each one is related to an object of the collection. The Id changes every time. I get {_id:1}, {_id:2}, {_id:3}, {_id:4}, {_id:5}, and {_id:6}. But, the backend keeps sending me the data of the object that is related to {_id:1}. That is why I keep receiving the same name of product.

This page brings me everything I need. This is HomeScreen, but when I make click on one of the products, it keeps sending the data from object {_id:1},

http://localhost:3003/product/1
http://localhost:3003/product/2
http://localhost:3003/product/3
http://localhost:3003/product/4
http://localhost:3003/product/5
http://localhost:3003/product/6

By God’s willing, I have found the solution:

But, I do not understand it sincerely. It was a matter of try and error. I will publish it in a moment.

This is my ProductScreen

import {Link} from 'react-router-dom';
import axios from 'axios';
import React,{useState,useEffect,useReducer} from 'react';
import {useParams} from 'react-router-dom';
import logger from 'use-reducer-logger';


const reducer = (state,action) => {
      switch(action.type){
           case  'FETCH_REQUEST':
              return {...state,loading: true};
              case  'FETCH_SUCCESS':
               return {...state,product: action.payload,loading:false};
               case 'FETCH_FAIL':
                  return {...state,loading:false,error: action.payload};
                 default:
                  return state;
               }
   };

   
 
function ProductScreen(props){
            
     const params = useParams();
     
     const {_id} = params; 
      

      const [{loading, error, product},dispatch] = useReducer(logger(reducer),{
            product: [],
            loading: true,
            error: '',
           }); 
          
         useEffect(()=>{
              const fetchData = async()=>{
               dispatch({type: 'FETCH_REQUEST'});
               try{
                  const result = await axios.get(`/api/products/${_id}`); 
                  dispatch({type: 'FETCH_SUCCESS',payload:result.data})
                  
               }catch(err){
                   dispatch({type: 'FETCH_FAIL', payload: err.message});
               }
                              
            };
              fetchData();
         },[_id]);
            
      return(
               <div>
                     {product.name}
               </div>
               
        )
  }

export default ProductScreen;

This is my HomeScreen

import React,{useState,useReducer,useEffect} from 'react';
import {Link } from 'react-router-dom';
import axios from 'axios';
import logger from 'use-reducer-logger';

const reducer = (state,action) => {
   switch(action.type){
        case  'FETCH_REQUEST':
           return {...state,loading: true};
           case  'FETCH_SUCCESS':
            return {...state,products: action.payload,loading:false};
            case 'FETCH_FAIL':
               return {...state,loading:false,error: action.payload};
              default:
               return state;
            }
};
function HomeScreen(){
   const [{loading, error, products},dispatch] = useReducer(logger(reducer),{
      products: [],
      loading: true,
      error: '',
     }); 
    
   useEffect(()=>{
        const fetchData = async()=>{
         dispatch({type: 'FETCH_REQUEST'});
         try{
            const result = await axios.get('/api/products'); 
            dispatch({type: 'FETCH_SUCCESS',payload:result.data})
            
         }catch(err){
             dispatch({type: 'FETCH_FAIL', payload: err.message});
         }
         const result = await axios.get('/api/products');
         
      };
        fetchData();
   },[]);
      return (
         
         <body>
              <nav>
                   <div className="menu-background">
                            {/*<p className="menu" >Amazonas</p>*/}
                            <Link to="/" className="menu" >amazonas</Link>

                  </div>
                  <div className="logo-background">
                            <p className="logo">Menu</p>
                 </div>
                
              </nav>
              
             <ul className="products">
          {
             products.map(product=>
             <li>
                <div className="product">
           <Link to={`/product/${product.name}`}>
           <img className="image" src={product.image} alt={product.name} ></img>
          </Link>

          <Link to={`/product/${product.name}`}>{product.name}</Link>
          
          <div className="rating">{product.rating}</div>
          <div className="price">{product.price}</div>
  </div>
</li>        
)
}
</ul>

    </body>
    
      )          
           }
export default HomeScreen;

This is my server:

import express from 'express';
import data from './data.js';

const app = express();

app.get('/api/products',(req,res)=>{
    res.send(data.products);
});

app.get('/api/products/:name',(req,res)=>{
    const product = data.products.find((x)=>x.name==req.params.name);
    if(product){
        res.send(product);
    }else{
        res.status(404).send({message: 'Product Is Not Found'});
    }
});

const port = process.env.PORT || 5000;
app.listen(port, () => {
    console.log(`serve at http://localhost:${port}`);
})

And this is my data.js

export default {
    /*image: '/images/T-Shirt.jpg',*/
    products: [
      {
        _id:1,
        name: 'T-Shirt-Hurley',
        rating: 4.8,
        image: '/images/T-Shirt.jpg',
        price: '$20'
        },
        {
        _id:2,
        name: 'Jean-Levi',
        rating: 4.2,
        image: '/images/Jean.jpg',
        price: '$30'
        },
        {
        _id:3,   
        name: 'Jacket-Quicksilver',
        rating: 4.5,
        image: '/images/Jacket.jpg',
        price: '$35'
        },
        {
        _id:4,
        name: 'T-Shirt-Adidas',
        rating: 4.8,
        image: '/images/T-Shirt-2.jpg',
        price: '$20'
        },
        {
        _id:5,
        name: 'Jean-Wrangler',
        rating: 4.2,
        image: '/images/Jean-2.jpg',
        price: '$30'
        },
        {
        _id:6,
        name: 'Jacket-Champion',
        rating: 4.5,
        image: '/images/Jacket-2.jpg',
        price: '$35'
         }

        ]
      }

Result:

Everything was in function of _id. I changed the endpoints as you mentioned to look for :name, and I did the same change in HomeScreen. The links were adjusted to product.name instead of product._id.

The only thing that worked with _id was ProductScreen, and it was because of useParams(). That was the same function you underlined too.

Everything should have worked with _id, but that was an incorrect conclusion.

This means the best way to communicate with the database is with name instead of _id., and I can conclujde that everything lastesd too much because of my incomprehension of how these functions work.

Thanks for the time.

In the data you posted, your _id is of type Number, but the param variable contains a string. So when you do x._id === req.params._id using strict equals, it does not match the type. But your name is of type String so it can match the param string.

So an implicit or explicit type conversion should work as well.


Using a product name as a unique identifier isn’t very reliable. I would switch back to using an id.

1 Like

I have tried by using equality operator (==), and it did not work either. Let me finish the scope of the project, and I will change that. Thanks for the explanation. It is meaningful to me.

Well if the same logic works with the name it can really only be one of two things, either you are not comparing the data correct (e.g. you did id and not _id), or the data type is wrong. There is absolutely no reason why you shouldn’t be able to find or filter using the id.