I have a site with cards and when you click on some card you need to see the same card but with another details. But everytime I click on some card I get this massgae in the terminal: Cast to ObjectId failed for value "undefined" (type string) at path "_id" for model "card"
Here What I wrote:
** CardDatails.jsx**
import React, { Component } from "react";
import PageHeader from "../common/pageHeader";
import { getCard } from "../../services/cardService";
class CardDetails extends Component {
state = {
card: {
adress: "",
bizNumber: "",
createdAt: "",
description: "",
image: { url: "", alt: "" },
likes: [],
phone: "",
title: "",
},
errors: {},
isMounted: false,
};
async componentDidMount() {
try {
const { data } = await getCard(this.props.id);
this.setState({ card: { card: data, isMounted: true } });
} catch (error) {
this.setState({ errors: error.massage });
}
}
render() {
const { card } = this.state;
const {
title,
description,
image: { url, alt },
address,
phone,
bizNumber,
createdAt,
likes,
} = card;
return (
<React.Fragment>
<PageHeader
title={`Business Card of: ${title}`}
subTitle={`Businness Description: ${description}`}
/>
<div className="card-body p-2">
<div>
<img
style={{ maxWidth: "400px" }}
src={url}
className="card-img"
alt={alt}
></img>
<br />
<strong>Tel: </strong>
{phone}
</div>
<div>
<strong>Address: </strong>
{address}
</div>
<div>
<strong>Card Number: </strong>
{bizNumber}
</div>
<div>
<strong>Created At: </strong>
{createdAt}
</div>
<div>
<strong>likes: </strong>
{likes}
</div>
</div>
</React.Fragment>
);
}
}
export default CardDetails;
App.js:
import { useParams } from "react-router-dom";
import CardDetails from "./CardDetails";
const CardDetailsConvertor = () => {
const { id } = useParams();
return <CardDetails id={id} />;
};
export default CardDetailsConvertor;
import HomePage from "./layout/main/Home";
import About from "./layout/main/About.jsx";
import { Routes, Route } from "react-router-dom";
import Error404 from "./layout/main/Error404";
import Header from "./layout/header/Header.jsx";
import Footer from "./layout/footer/footer.jsx";
import BizSignup from "./layout/main/BizSignup";
import Logout from "./layout/main/Logout";
import MyCards from "./layout/main/MyCards";
import MyFavoriteCards from "./layout/main/MyFavoriteCards";
import Login from "./layout/main/Login";
import Signup from "./layout/main/Signup";
import { ToastContainer } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import { getCurrentUser } from "./services/userService";
import CreateCard from "./layout/main/CreateCard";
import EditCardConvertor from "./layout/main/editCardConvertor";
import CardDetails from "./layout/main/CardDetails";
import CardDetailsConvertor from "./layout/main/CardDetailsConvertor";
function App() {
const user = getCurrentUser();
return (
<div className="App">
<Header user={user} />
<ToastContainer />
<main style={{ minHeight: "85vh" }}>
<Routes>
<Route path="/about" element={<About />} />
<Route path="/biz-signup" element={<BizSignup />} />
<Route path="/logout" element={<Logout />} />
<Route path="/my-cards" element={<MyCards user={user} />} />
<Route path="/create-card" element={<CreateCard user={user} />} />
<Route
path="/card-details-converotr"
element={<CardDetailsConvertor user={user} />}
/>
<Route
path="/edit-card/:id"
element={<EditCardConvertor user={user} />}
/>
<Route path="/card-details/:id" element={<CardDetails />} />
<Route
path="/my-fav-cards"
element={<MyFavoriteCards user={user} />}
/>
<Route path="/login" element={<Login />} />
<Route path="/signup" element={<Signup />} />
<Route path="/" element={<HomePage />} />
<Route path="*" element={<Error404 />} />
</Routes>
</main>
<Footer />
</div>
);
}
export default App;
**CardDetailsConverotr.jsx:**
import { useParams } from "react-router-dom";
import CardDetails from "./CardDetails";
const CardDetailsConvertor = () => {
const { id } = useParams();
return <CardDetails id={id} />;
};
export default CardDetailsConvertor;
So if you can help I will be happy Thank you!
CodePudding user response:
CardDetails
component isn't passed any props, so this.props.id
is undefined.
<Route
path="/card-details/:id"
element={<CardDetails />} // <-- no props are passed here
/>
You can either convert CardDetails
to a functional component so it can use the useParams
hook to access the id
route param, or you can create a custom withRouter
Higher Order Component to do this and inject the params as a prop to be accessed in component.
I won't cover conversion, but the following is a simple withRouter
HOC:
import { useParams } from 'react-router-dom';
const withRouter = Component => props => {
const params = useParams();
return <Component {...props} params={params} />;
};
...
import React, { Component } from "react";
import PageHeader from "../common/pageHeader";
import { getCard } from "../../services/cardService";
import { withRouter } from "../path/to/withRouter";
class CardDetails extends Component {
state = {
...
};
async componentDidMount() {
try {
const { data } = await getCard(this.props.params.id);
this.setState({ card: { card: data, isMounted: true } });
} catch (error) {
this.setState({ errors: error.massage });
}
}
render() {
const { card } = this.state;
const {
title,
description,
image: { url, alt },
address,
phone,
bizNumber,
createdAt,
likes,
} = card;
return (
...
);
}
}
export default withRouter(CardDetails);