Cannot Read image of undefined in React app - reactjs

I'm use the filter method to pick-out one featured item in an array and use that to render it's state in my Home Component. I'm using the filter method in the MainComponent, passing that to the Home Component, where I want the AddCard functional component to render. I'm getting the error message of "cannot read image of undefined" so I'm assuming I'm doing something wrong in passing my props.
MainComponent.js
class Main extends Component{
constructor(props){
super(props);
this.state={
whyfastpack: WHYFASTPACK
};
}
render(){
const LandingPage =()=>{
return (
<Landing />
);
};
const HomePage=()=>{
return (
<Home
lightweight={this.state.whyfastpack.filter(lightweight => lightweight.featured)[0]}
/>
);
};
return(
<div>
<Header />
<Switch>
<Route exact path='/' component={LandingPage} />
<Route path ='/home' component={HomePage} />
HomeComponent.js
...
</div>
<div className='col-md m-1'>
<AddCard />
</div>
</div>
....
function RenderCard({ item }) {
return (
<Card>
<CardImg src={this.image} alt={item.name} />
<CardBody>
<CardTitle>{item.name}</CardTitle>
<CardText>{item.comment}</CardText>
</CardBody>
</Card>
);
}
function AddCard(props) {
return (
<div className="container">
<div className="row">
<div className="col-md m-1">
<RenderCard item={props.lightweight} />
</div>
</div>
</div>
);
}
whyFastPack.js
export const WHYFASTPACK = [
{
id: 0,
image: 'images/pnw.jpg',
name: 'Reduce Weight',
comment: 'Carry only what you need for the day, not a month! With fast-packing you only need to bring enough to get you through each day!',
featured: true,
}
]

You neglected to pass a lightweight prop to AddCard from HomeComponent.
<div className='col-md m-1'>
<AddCard lightweight={this.props.lightweight} />
</div>

Related

How to send multiple elements as React children and position individually where you want

The structure should look like this:
<Modal>
<Header />
<Body />
<Footer />
</Modal>
The output should look like this
<div>
<header>
<Header />
</header>
<main>
<Body />
</main>
<footer>
<Footer />
</footer>
</div>
You can select the passed children by their index and position them.
Here's how to achieve the solution,
const Modal = ({children}) => {
return (
<div>
<header>
{ children[0] }
</header>
<main>
{ children[1] }
</main>
<footer>
{ children[2] }
</footer>
</div>
)
}
We have this option to specify different spaces for multiple components. In React, we don't but this action can be done by passing props. Like this:
<MyComponent
headerComponent={<Header />}
bodyComponent={<Body />}
footerComponent={<Footer />}
>
</div>
And in MyComponent:
const MyComponent = (props) => {
return (
<div>
{props.headerComponent}
{props.bodyComponent}
{props.footerComponent}
</div>
)
}
const Modal = ({ children }) => {
return (
<React.Fragment>
<header>{children[0]}</header>
<main>{children[1]}</main>
<footer>{children[2]}</footer>
</React.Fragment>
)};
or
const Modal = ({ children }) => {
return (
<>
<header>{children[0]}</header>
<main>{children[1]}</main>
<footer>{children[2]}</footer>
</>
)};
which does the same things.

props in app does not work in other component

Currently I'm working on a project for a customer. I am building my frontend in ReactJs and I should use a loggedIn check. While I'm loggedIn I want to change my button Log Out. And by a product I want to show in cart, but it does not show anything at all by loggedIn: true in App.js
Code:
App.js
state = {
name: "Tapijtboerderij",
winkelmand: 0,
gebruiker: null,
product: null,
loggedIn: true
}
render() {
return (
<div className="App" >
<Menu props={this.state} />
}
Menu.js (made in React.Router)
A line of code to router to component.
import React from 'react'
import { BrowserRouter as Router, Route } from "react-router-dom";
import LinkTo from './link';
import Index from "../pages/index";
import Tapijt from "../pages/tapijt";
import Vloeren from "../pages/vloeren";
import Zonwering from "../pages/zonwering";
import Gordijnen from "../pages/gordijnen";
import Contact from "../pages/contact";
import Login from "../pages/login";
import Product from "../pages/product";
import Page404 from "../pages/404";
import AlgemeneVoorwaarden from "../voorwaarden/algemene-voorwaarden";
import CookieBeleid from "../voorwaarden/cookie-beleid";
import PrivacyBeleid from "../voorwaarden/privacy-beleid";
import Sitemap from "../voorwaarden/sitemap";
import logo from "../logo/logo.jpg";
import Button from "./button";
export default class Menu extends React.Component {
constructor(props) {
super(props);
this.state = {
collapsed: false,
widthOverlay: 0
}
}
collapseMenu = () => {
let strepen = document.querySelectorAll(".streep");
if (this.state.collapsed === false) {
strepen[0].style.transform = "rotate(-45deg)";
strepen[0].style.marginTop = "7px";
strepen[1].style.display = "none";
strepen[2].style.transform = "rotate(45deg)";
strepen[2].style.marginTop = "-7px";
this.setState({
collapsed: !this.state.collapsed,
widthOverlay: "60%"
});
} else {
strepen[0].style.transform = "rotate(0deg)";
strepen[0].style.marginTop = "0";
strepen[1].style.display = "block";
strepen[2].style.transform = "rotate(0deg)";
strepen[2].style.marginTop = "0";
this.setState({
collapsed: false,
widthOverlay: 0
})
}
}
render() {
return (
<Router>
<nav className="menu">
<div className="container">
<a href="/" className="brand-logo to-left">
<img src={logo} className={"menu-logo"} alt={"logo bedrijf"} />
</a>
<div className={"links to-right menu-laptop"}>
<div className={"menu-links-laptop"}>
<LinkTo to="/" name={"Home"} />
<LinkTo to="/src/pages/tapijt" name={"Tapijt"} />
<LinkTo to="/src/pages/vloeren" name={"Vloeren"} />
<LinkTo to="/src/pages/zonwering" name={"Zonwering"} />
<LinkTo to="/src/pages/gordijnen" name={"Gordijnen"} />
<LinkTo to="/src/pages/contact" name={"Contact"} />
{this.props.loggedIn ? <Button link={"/src/pages/login"} buttonName={"Log uit"} /> : <Button link={"/src/pages/login"} buttonName={"Log in"} />}
</div>
</div>
</div>
</nav>
<div className="sidenav" id="mobile-demo" style={{
width: `${this.state.widthOverlay}`
}}>
<div className={"menu-icon"} onClick={this.collapseMenu}>
<div className={"strepen"}>
<div className={"streep"} />
<div className={"streep"} />
<div className={"streep"} />
</div>
</div>
<div className={"links-mobile"}>
<LinkTo to="/" name={"Home"} />
<LinkTo to="/src/pages/tapijt" name={"Tapijt"} />
<LinkTo to="/src/pages/vloeren" name={"Vloeren"} />
<LinkTo to="/src/pages/zonwering" name={"Zonwering"} />
<LinkTo to="/src/pages/gordijnen" name={"Gordijnen"} />
<LinkTo to="/src/pages/contact" name={"Contact"} />
<LinkTo to="/src/pages/login" name={"Log in"} />
</div>
</div>
<Route path="/" exact component={Index} />
<Route path="/src/pages/tapijt" component={<Tapijt loggedIn={this.props.loggedIn} />} />
<Route path="/src/pages/vloeren" component={Vloeren} />
<Route path="/src/pages/zonwering" component={Zonwering} />
<Route path="/src/pages/gordijnen" component={Gordijnen} />
<Route path="/src/pages/contact" component={Contact} />
<Route path="/src/pages/login" component={Login} />
<Route path="/src/pages/product" component={Product} />
<Route path="/src/pages/404" component={Page404} />
<Route path="/src/voorwaarden/algemene-voorwaarden" component={AlgemeneVoorwaarden} />
<Route path="/src/voorwaarden/cookie-beleid" component={CookieBeleid} />
<Route path="/src/voorwaarden/privacy-beleid" component={PrivacyBeleid} />
<Route path="/src/voorwaarden/sitemap" component={Sitemap} />
</Router >
);
}
}
Tapijt.js
render() {
return (
<div className={"container"}>
<h1 className={"header"}>Tapijten</h1>
<div className={"parent"}>
<div className={"flex"}>
{tapijten.map((tapijt, identifier) =>
<Card key={identifier}
photo={TapijtImg}
productHeader={tapijt}
productContent={"Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of \"de Finibus Bonorum et Malorum\" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, \"Lorem ipsum dolor sit amet..\", comes from a line in section 1.10.32."}
link={"./product"}
buttonName={"Ga naar Product"}
loggedIn={this.state.loggedIn} />)}
</div>
</div>
</div>
)
}
Product.js
import React from 'react';
import ProductImage from "../images/tapijt.jpg";
import Button from "../components/button";
let productSpecifications = [["Lengte: ", 1200], ["Breedte: ", 1000], ["Soort: ", "Hoogpolig
saxony"], ["Prijs per vierkante M(2): ", 4.85]];
class Product extends React.Component {
constructor(props) {
super(props);
this.state = {
data: productSpecifications
}
}
render() {
return (
<div className={"container top-40"}>
<div className={"flex half-om-half"}>
<div className={"product-photo"}>
<img src={ProductImage} className={"product-img"} alt={"product foto"} />
</div>
<div className={"product-info"}>
<h1 className={"product-header"}>Product Header can Kania</h1>
<p>
Is it possible to use CSS pseudo-classes to select even and odd instances of list items?
I'd expect the following to produce a list of alternating colors, but instead I get a list of blue items:
</p>
<h2 className={"product-price"}>679,-</h2>
{/*{this.props.loggedIn ? <Button link={"#"} buttonName={"In Winkelmand"} /> : ""}*/}
{this.props.loggedIn ? <Button backgroundColor={"var(--success-color)"} color={"var(--white)"} link={"#"} buttonName={"In Winkelmand"} /> : ""}
</div>
</div>
<div className={"product-specifications"}>
<h2>Details</h2>
<table>
<tbody>
{this.state.data.map((data) => <ul>{data}</ul>)}
</tbody>
</table>
</div>
</div>
)
}
}
export default Product;
Thank you in advance
First of all your Route is wrong.
<Route path="/src/pages/tapijt" component={<Tapijt loggedIn={this.props.loggedIn} />} />
It should be
<Route path="/src/pages/tapijt" render={(props) => (<Tapijt loggedIn={this.props.loggedIn} {...props}/>)}/>
Unless you handle it somewhere else not showing in current code snippet, you pass the loggedIn value to Tapijt component but you don't handle it somehow. you are using a state property loggedIn.
Maybe this
buttonName={"Ga naar Product"}
loggedIn={this.state.loggedIn} />)}
should be this?
buttonName={"Ga naar Product"}
loggedIn={this.props.loggedIn} />)}
just to be on the same page.
You are passing your Props Object called state from App.js to the Menu Component.
So I assume that you check for the this.props.state inside the Menu Component right ?
<Route path="/src/pages/tapijt" component={<Tapijt loggedIn={this.props.loggedIn} />} />
Where does this line of code comes from ?
Right now I'm missing the context, where you pass your Props ( loggedIn: true / false ) to your Product.js
It would be great if you could share the could over CodePen or JSFiddle for e.g.
EDIT:
You can try doing it like this:
// Inside of App.js
const userInfo = {
name: "Tapijtboerderij",
winkelmand: 0,
gebruiker: null,
product: null,
loggedIn: true
}
render() {
return (
<div className="App" >
<Menu {...userInfo} />
</div>
}
// Inside of Menu.js
export default class Menu extends React.Component {
...
constructor(props) {
super(props);
this.state = {
collapsed: false,
widthOverlay: 0
}
}
...
render() {
return(
<Router>
<nav className="menu">
<div className="container">
<a href="/" className="brand-logo to-left">
<img src={logo} className={"menu-logo"} alt={"logo bedrijf"} />
</a>
<div className={"links to-right menu-laptop"}>
<div className={"menu-links-laptop"}>
<LinkTo to="/" name={"Home"} />
<LinkTo to="/src/pages/tapijt" name={"Tapijt"} />
<LinkTo to="/src/pages/vloeren" name={"Vloeren"} />
<LinkTo to="/src/pages/zonwering" name={"Zonwering"} />
<LinkTo to="/src/pages/gordijnen" name={"Gordijnen"} />
<LinkTo to="/src/pages/contact" name={"Contact"} />
{this.props.loggedIn ? <Button link={"/src/pages/login"} buttonName={"Log uit"} /> : <Button link={"/src/pages/login"} buttonName={"Log in"} />}
</div>
</div>
</div>
</nav>
...
</Router>
)
}
...
}
// Inside of Product.js
class Product extends React.Component {
constructor(props) {
super(props);
this.state = {
data: productSpecifications
}
}
...
render() {
return(
...
{this.props.loggedIn ? <Button backgroundColor={"var(--success-color)"} color={"var(--white)"} link={"#"} buttonName={"In Winkelmand"} /> : ""}
...
)
}
}
```
By using the Spread Attributes like so: `...userInfoà it also make it easy to pass unnecessary props to components.
I hope it helps you.

Problem to render a component dynamically with React Router

I'm working on a personal website and I have a problem rendering a component dynamically using React Router. To me, everything seems correct but for some reason, it's not working.
I tried to follow the documentation and watched a couple of tutorials but I have been stuck for a long time so I feel like I need help on this one.
In this component, I want to render the 'Articles' component dynamically using the id
class JobCard extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
};
}
componentWillMount() {
fetch(url)
.then(data => data.json())
.then(result =>
this.setState({
data: result
})
);
}
render() {
const { match } = this.props;
const { data, value } = this.state;
return (
<>
<div>
{results.map((job, id) => (
<div key={id}>
<div key={job._id} className="blog-card">
<div className="meta">
<div className="photo">
<img src={job.img} alt="logo" />
</div>
</div>
<div className="description">
<h5>{job.position_name}</h5>
<p className="read-more">
<p>{job.location}</p>
<p>
<span className="learn-pow">
{" "}
<Link
to={{
pathname: `${match.url}/${job._id}`,
state: job
}}
>
{job.workplace_name}
</Link>{" "}
Enter Location
</span>
</p>
</p>
</div>
</div>
</div>
))}
</div>
}
<Route path={`${match.path}/:id`} component={Articles} />
</>
);
}
}
export default JobCard;
And here is the component that i want to render:
import React from 'react';
const Articles = ({ location }) => (
<div>
<h1>{location.state.name}</h1>
<h2>{location.state.email}</h2>
<h2>{location.state.place}</h2>
</div>
)
export default Articles;
When I click on the Card the URL is right so I get the id but I don't have access to the Article component. I tried to console log but nothing appears.
Instead of this
<Route path={`${match.path}/:id`} component={Articles} />
try doing this
<Route path={`${match.url}/:id`} component={Articles} />

How can I get a component to update on path change while using the same route and component?

When the user is viewing another users profile, and attempt to click their own profile link in the navbar, the component never updates. In both the Redux and React dev tools, it shows that the state has been updated correctly but the component doesnt seem to notice and update.
class App extends Component {
render() {
return (
<Router>
<div>
<Navbar />
<NavbarFix />
<Switch>
<Route exact path="/" component={Posts} />
<Route exact path="/submit" component={AuthRoute(Submit)} />
<Route exact path="/signup" component={AlreadyAuth(SignUp)} />
<Route exact path="/login" component={AlreadyAuth(LogIn)} />
<Route exact path="/user/:id" component={AuthRoute(User)} />
<Route exact path="/item/:id" component={AuthRoute(Item)} />
<Route exact path="/admin" component={AdminAuth(Admin)} />
<Route exact path="/banned" component={Banned} />
<Route component={NoMatch} />
</Switch>
</div>
</Router>
);
}
}
.
class User extends Component {
constructor(props) {
super(props);
this.state = {
posts: [],
user: [],
comments: []
};
}
componentDidMount() {
this.loadUser();
}
loadUser = () => {
API.findUserById(this.props.match.params.id)
.then(res => {
console.log(res.data);
this.setState({
user: res.data.user,
posts: res.data.user.Posts,
comments: res.data.comments
});
console.log(this.state)
})
.catch(err => console.log(err));
this.setState(this.state)
}
handleCommentDelete = id => {
API.deleteComment(id)
.then(res => this.loadUser())
.catch(err => console.log(err));
}
handlePostDelete = id => {
API.deletePost(id)
.then(res => this.loadUser())
.catch(err => console.log(err));
}
render() {
return (
<div>
<div className="container-fluid">
<div className="row">
<div className="col-4 user-data-container">
<div className="row">
<div className="col-12 text-center">
<h2>{this.state.user.username}'s Posts</h2>
</div>
</div>
<hr className="pb-4" />
<div className="row">
<div className="col-12">
{this.state.posts.length > 0 ?
this.state.posts.map(post => (
<PostContainer handledelete={this.handlePostDelete} post={{ ...post, User: this.state.user }} key={post.id} check={this.props.id} />
))
:
<h1>No Posts To Show!</h1>
}
</div>
</div>
</div>
<div className="col-4 user-data-container">
<div className="row">
<div className="col-12 text-center">
<h2>{this.state.user.username}'s Comments</h2>
</div>
</div>
<hr className="pb-4" />
<div className="row">
<div className="col-12">
{this.state.comments.length > 0 ?
this.state.comments.map(comments => (
<CommentContainer verified={this.state.user.verified} handledelete={this.handleCommentDelete} check={this.props.id} comment={comments} className="hover-effect single-comment" key={comments.id}/>
))
:
<h1>No Comments To Show!</h1>
}
</div>
</div>
</div>
<div className="col-4 user-data-container">
<div className="row">
<div className="col-12 text-center">
<h2>{this.state.user.username}'s Information</h2>
</div>
</div>
<hr className="pb-4" />
<div className="row">
<div className="col-12">
<UserContainer user={this.state.user}/>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}
const mapStateToProps = state => {
return {
username: state.auth.username,
id: state.auth.id,
email: state.auth.email,
profileImg: state.auth.profileImg,
verified: state.auth.verified
};
};
export default withRouter(connect(mapStateToProps)(User));
I believe this has to do with the same route and component being used, so the change isn't actually noticed. Is there any way to fix this? To my understanding, the component should be updating on state change.
If the link is directing to the same route with just a different param, it will not remount/componentDidMount will not be called again.
So, you could use the componentWillReceiveProps(newProps) lifecycle function and look for newProps.match.params.id and compare it with this.props.match.id and if different call loadUser again.
**You would also need to change your loadUser function to accept an id param
(Param validation not included)
componentDidMount() {
this.loadUser(this.props.match.id);
}
loadUser = (id) => {
API.findUserById(id)..
…
}
componentWillReceiveProps(newProps) {
if(newProps.match.params.id !== this.props.match.id) {
this.loadUser(newProps.match.params.id)
}
}

React with FlowRouter: How to show/hide component based on route

I have a Meteor application that I'm developing using React and I do my routing using FlowRouter. My main AppContainer for the project has a bunch of components, one of them being the footer.
class AppContainer extends Component {
render() {
return(
<div className="hold-transition skin-green sidebar-mini">
<div className="wrapper">
<Header user={this.props.user} />
<MainSideBar />
{this.props.content}
<Footer />
<ControlSideBar />
<div className="control-sidebar-bg"></div>
</div>
</div>
)
}
}
I have a few routes that go to various chat rooms:
Eg.
/chatroom/1
/chatroom/2
/chatroom/3
Is there a way for me to hide the <Footer /> component if the route is a /chatroom/<anything>?
You can maybe do a conditional rendering by checking the current path.
If the <anything> part (I assume it is a parameter) after the /chatroom/ is not important, and if you do not have any other routing that starts with chatroom, you can try this one:
const currentPath = window.location.pathname
{!currentPath.includes('chatroom') ? <Footer /> : null }
So your code would look like this:
class AppContainer extends Component {
render() {
currentPath = window.location.pathname
return(
<div className="hold-transition skin-green sidebar-mini">
<div className="wrapper">
<Header user={this.props.user} />
<MainSideBar />
{this.props.content}
{!currentPath.includes('chatroom')
? <Footer />
: null }
<ControlSideBar />
<div className="control-sidebar-bg"></div>
</div>
</div>
)
}
}
If <anything> part is important and/or you have other routes that starts with chatroom, you can first get the parameter of the route with
const param = FlowRouter.getParam('someParam');
and then do the conditional rendering by checking if the current path contains the chatroom/:param like this:
const currentPath = window.location.pathname
{!currentPath.includes(`chatroom/${param}`) ? <Footer /> : null }
So your code would look like this
class AppContainer extends Component {
render() {
const currentPath = window.location.pathname
const param = FlowRouter.getParam('someParam');
return(
<div className="hold-transition skin-green sidebar-mini">
<div className="wrapper">
<Header user={this.props.user} />
<MainSideBar />
{this.props.content}
{!currenPath.includes(`chatroom/${param}`)
? <Footer />
: null }
<ControlSideBar />
<div className="control-sidebar-bg"></div>
</div>
</div>
)
}
}
You can also use the following syntax below. It accomplishes the same thing as the first example provided by Cagri Yardimci.
{ !currentPath.includes('chatroom') && <Footer /> }

Resources