Unable to read attributes of props in React - javascript

I'm building a winery themed shopping app in React and I'm using functional components. I have 12 products (wines) displayed on one page, and I want to make a separate page for each wine when the user clicks on it.
This is how I handled routes:
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/products" element={<Products wines={products}/>} />
<Route path="/contact" element={<Contact />} />
<Route path="/cart" element={<Cart />} />
{wines.map((wine) => (
<Route key={wine.id} path={`/shop/${wine.id}`} element={<Item item={wine} />}/>
))}
</Routes>
</BrowserRouter>
I mapped through all of the wines and created a separate route for each of them, and sent a particular wine as a prop to each "Item" component.
Item component looks like this:
const Item = (item) => {
return (
<>
<Header />
<div className="item_container">
<img className="item_image" alt={item.name} src={item.image} />
<h1 className="item_name">{item.name}</h1>
<h3 className="item_price">{item.price}</h3>
</div>
<Footer />
</>
)
When I console log "item" in this component, I get the specific wine and I can see all of its attributes (name, price, image URL), but when I try to access those attributes in order to display them (item.name, item.image, item.price), the console logs "undefined".
How can i fix this?

You've passed a item prop to the Item component.
<Item item={wine} />
And then named the props object item in the Item component.
const Item = (item) => { ... }
Either rename to props and correctly access props.item.xxx
const Item = (props) => {
const { item } = props;
return (
<>
<Header />
<div className="item_container">
<img className="item_image" alt={item.name} src={item.image} />
<h1 className="item_name">{item.name}</h1>
<h3 className="item_price">{item.price}</h3>
</div>
<Footer />
</>
);
}
or destructure item directly
const Item = ({ item }) => (
<>
<Header />
<div className="item_container">
<img className="item_image" alt={item.name} src={item.image} />
<h1 className="item_name">{item.name}</h1>
<h3 className="item_price">{item.price}</h3>
</div>
<Footer />
</>
);
An optimization I'd suggest is to declare a single route with the wine id as a route path param, and then access the wines array in Item.
Example:
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/products" element={<Products wines={products}/>} />
<Route path="/contact" element={<Contact />} />
<Route path="/cart" element={<Cart />} />
<Route path="/shop/:wineId" element={<Item />} />
</Routes>
</BrowserRouter>
...
import { useParams } from 'react-router-dom';
const Item = () => {
const { wineId } = useParams();
const wine = wines.find(wine => wine.id === wineId);
if (!wine) return <div>No wine found.</div>;
return (
<>
<Header />
<div className="item_container">
<img className="item_image" alt={wine.name} src={wine.image} />
<h1 className="item_name">{wine.name}</h1>
<h3 className="item_price">{wine.price}</h3>
</div>
<Footer />
</>
);
}

Please check null and empty array for "wines" first , if not null then map through "wines"

Related

React webpage refreshing every 4-6 seconds

I'm not really sure even what part of my code to show because it's such a general error, but everytime I npm start my React webpage it automatically goes from the home page to the authentication dashboard and starts refreshing.
I'm guessing it's a problem with React Router but I'm not really sure about this either?
This is how my App.js App component currently looks, which has the main Route functionality.
const App = () => {
const [auth, setAuth] = useState(false);
useEffect(() => {
localStorage.setItem("user", auth);
}, [auth]);
return (
<div className="landing" style={{zIndex:0, margin:"0px", position:"fixed"}}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
{!auth && (
<Route
path="/auth"
element={
<Auth authenticate={(val) => setAuth(val === 1 ? true : false)} />
}
/>
)}
{auth && (
<>
<Route path="/dashboard" element={<Dashboard />} />
</>
)}
<Route
path="*"
element={<Navigate to={auth ? "/dashboard" : "/auth"} />}
/>
</Routes>
</div>
);
}
And this is how my Home.js Home component file looks like
function Home() {
return (
<div className="main">
<div className="landingImageDiv">
<img src={ligaLogo} alt="uchisvg" className="landingImage" />
<div id="fade" className="linkDiv topMargin5">
<div>
<Link to="/about" className="popupLink">
<span className="hover">[About]</span>
</Link>
</div>
<div>
<Link to="/auth" className="popupLink">
<span className="hover">[Talent Network]</span>
</Link>
</div>
<div>
{/* Format to request access to platform */}
<a href="https://forms.gle/vKzq5M9n56oKKV5DA" className="popupLink">
<span className="hover">[Request RSO Onboarding]</span>
</a>
</div>
</div>
</div>
<div className="landing" id="fade">
<div style={{ zIndex: 5, position: "relative" }}></div>
</div>
</div>
);
}
Change your route definition as follows:
{
!auth ? (
<Route
path="/auth"
element={
<Auth authenticate={(val) => setAuth(val === 1 ? true : false)} />
}
/>
) : (
<>
<Route path="/dashboard" element={<Dashboard />} />
</>
);
}

No routes matching location "/dash/1"

I have the following problem. my route is not registered and i dont know why.
Links
dashboard.jsx
this code generates all the links.
<div className="flex w-3/4 m-auto flex-col mt-10 xl:w-1/2">
{questions.map(({ id, question }) => {
return (
<Link to={`/dash/${id}`}>
<QuestionHeader question={question} />
</Link>
);
})}
</div>
/dash/1,/dash/2,.... are generated by the map function above.
i have two files that represent the routes.
NavRoutes
const NavRoutes = () => {
return (
<Routes>
<Route path="/:id" element={<Question />} />
<Route path="" element={<Dashboard />} />
</Routes>
);
};
export default NavRoutes;
here is the Main component
const Main = () => {
return (
<div>
<NavBar />
<NavRoutes />
<Footer />
</div>
);
};
export default Main;
and the main routes for authentication and accessing the main page
const App = () => {
let { user } = useAuthContext();
return (
<div className="w-full bg-slate-700 block fixed h-full">
<Header />
<Router>
<Routes>
<Route
path="/dash"
element={!user ? <Navigate to="/auth" /> : <Main />}
>
</Route>
<Route path="" element={<Login />} />
</Routes>
</Router>
</div>
);
};
when i try to access /dash/1, i get the following error
router.ts:11 No routes matched location "/dash/1"
Did you try the following in your NavRoutes (prepending '/dash' to '/:id'):
<Route path="/dash/:id" element={<Question />} />
i solved this by doing the following
const App = () => {
let { user } = useAuthContext();
return (
<div className="w-full bg-slate-700 block fixed h-full">
<Header />
<Router>
<Routes>
<Route
path="/dash/*"
element={!user ? <Navigate to="/auth" /> : <Main />}
>
</Route>
<Route path="/auth" element={<Login />} />
</Routes>
</Router>
</div>
);
};
you need to include a * when nesting deeper

Nested routes in react-router-dom

enter image description here
How to navigate through the tabs in react.
Since I am currently in a tab, I have already used react route and the nested route does not work. how to make a transition through the masonry. Through a nested route or otherwise?
I have a react application inside this I have component with my routers
export const Container = (props) => {
return (
<Switch>
<Route exact path="/">
<Redirect to={PERSONAL} />
</Route>
<Route path={PAGE} render={() => <PicturesMainPage />} />
<Route path={PERSONAL} render={() => <PersonalPage />} />
<Route path={PERSONAL_SETTINGS} render={() => <PersonalSettingsPage />} />
</Switch>
);
};
In this component I have inside this component I drow an information about user with menu and i wand to drow athother components for click in to menu
export const PersonalPage = () => {
return (
<div className="container">
<PersonalInfo />
<div className="personal-area__galery">
<Switch>
<Route exact path={PERSONAL}>
<Redirect to={PERSONAL_GALLERY} />
</Route>
<Route path={PERSONAL_GALLERY} render={() => <Gallery images={images} />} />
<Route path={PERSONAL_COLLECTIONS} render={() => <Collections />} />
<Route path={PERSONAL_STATISTICS} render={() => <Statistics />} />
</Switch>
</div>
</div>
);
};
Person info
let menu = [
{ href: PERSONAL_GALLERY, text: 'Галерея' },
{ href: PERSONAL_COLLECTIONS, text: 'Коллекции' },
{ href: '/personal/statistics', text: 'Статистика' },
];
let person = {
profileName: 'Top Waifu',
profileTag: '#topwaifu',
profileDescription: 'Самая топовая вайфу твоего района',
subscribers: '5.1m',
subscriptions: 246,
};
export const PersonalInfo = (props) => {
return (
<div>
<div className="personal-area__profile">
<div className="personal-area__profile__description">
<PersonalAvatar img={'assets/img/testImg4.png'} />
<PersonalDescription
profileName={person.profileName}
profileTag={person.profileTag}
profileDescription={person.profileDescription}
subscribers={person.subscribers}
subscriptions={person.subscriptions}
/>
<div className="personal-area__profile__description__icons">
<Share />
<Settings />
<MoreOptions />
</div>
</div>
</div>
<div className="personal-area__menu">
<ul>
{menu.map((elem, i) => (
<MenuElement key={i} menulink={elem.href} menuName={elem.text} />
))}
</ul>
</div>
</div>
);
};
take a look at this codesandbox I made.
https://codesandbox.io/s/frosty-cdn-1fn0u?file=/src/App.js
Here you can see a clear example of nesting routes.

How to change props.data in dependence of inner component?

ProductPage
MainPage
I want to click on product on MainPage and Open info about it on ProductPage. I want to open exactly that product, that i had clicked on MainPage.
I have an App.js with router. When I click on ProductCard component in MainPage i want to open ProductPage exactly with that props, that shows in ProductCard. How can I do this?
App.js:
<BrowserRouter>
<div className="App">
<Switch>
<Route path="/LoginPage" component={LoginPage} />
<Route exact
path="/"
render={() => <MainPage data={data} />}
//data={data}
/>
<Route path="/RegistrationPage" component={RegistrationPage} />
<Route path="/ProductPage" component={ProductPage} />
</Switch>
</div>
</BrowserRouter>
MainPage:
<div className="product-cards">
{props.data.map(function(item, index) {
return <ProductCard key={index} data={item} />;
})}
</div>
ProductCard:
<a className="a" href="/ProductPage">
<div className="card-block">
<img
className="image-style"
src={props.data.url}
alt={props.data.name}
/>
<span className="product-name">{props.data.name}</span>
</div>
</a>
ProductPage(shows error):
<div className="product-page">
<hr className="hr" />
<div class="product-description">
<img src={props.data.url} alt={props.data.name}/>
</div>
</div>
You aren't passing any props to Product Page which is causing error.
<BrowserRouter>
<div className="App">
<Switch>
<Route path="/LoginPage" component={LoginPage} />
<Route
exact
path="/"
render={() => <MainPage data={data} />}
/>
<Route path="/RegistrationPage" component={RegistrationPage} />
<Route path="/ProductPage"
render={() => <ProductPage data={data} />} />
</Switch>
</div>
</BrowserRouter>;

Showing two component in the same path inside a switch

I need to set a switch that shows containers components and a login form when the user is not authenticated on each of the main component.
I found another solution that tells you to wrap two components inside a div to use it in the same path inside a switch. But the problem is that some of my components use a req.params from the path that are not passed to the components when they're wrapped in a div
function Routes(props) {
const noLoggedIn = [
{
path: "/",
exact: true,
component: () => <div>
<EventsListContainer />
<LoginFormContainer />
</div>
},
{
path: "/events/:id",
exact: false,
component: () => <div>
//when the component is mounted it doesn't get the :id
<EventDetailsContainer />
<LoginFormContainer />
</div>
}
]
return (<div>
{!props.authenticated &&
<Switch>
{noLoggedIn.map((route, index) =>
<Route
key={index}
path={route.path}
exact={route.exact}
component={route.component}
/>
)}
</Switch>}
{props.authenticated &&
<Switch>
<Route exact path="/" component={EventsListContainer} />
<Route exact path="/" component={CreateEventFormContainer} />
//here the component gets the :id
<Route path="/events/:id" component={EventDetailsContainer} />
<Route path="/events/:id" component={CreateTicketFormContainer} />
</Switch> }
</div>)
}
Try as follows -
<Route path='/some-path' render={props =>
<div>
<FirstChild />
<SecondChild />
</div>
} />
you can also do it like as follows -
render((
<Router>
<Route path="/" component={App}>
<Route path="groups" components={{main: Groups, sidebar: GroupsSidebar}} />
<Route path="users" components={{main: Users, sidebar: UsersSidebar}}>
<Route path="users/:userId" component={Profile} />
</Route>
</Route>
</Router>
), node)
class App extends React.Component {
render() {
// the matched child route components become props in the parent
return (
<div>
<div className="Main">
{/* this will either be <Groups> or <Users> */}
{this.props.main}
</div>
<div className="Sidebar">
{/* this will either be <GroupsSidebar> or <UsersSidebar> */}
{this.props.sidebar}
</div>
</div>
)
}
}
class Users extends React.Component {
render() {
return (
<div>
{/* if at "/users/123" this will be <Profile> */}
{/* UsersSidebar will also get <Profile> as this.props.children.
You can pick where it renders */}
{this.props.children}
</div>
)
}
}
Example from - https://github.com/ReactTraining/react-router/blob/v3/docs/API.md#named-components

Categories

Resources