Reputation: 15
I'm not sure why my app keeps saying undefined. The error originated on line 21 of Album.js: <img id="album-cover-art" src={this.state.album.albumCover}/>
I believe I need to add this.state.album
somewhere, but I'm not sure where.
Index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>
, document.getElementById('root'));
registerServiceWorker();
App.js:
import React, { Component } from 'react';
import { Route, Link } from 'react-router-dom';
import './App.css';
import Landing from './components/Landing';
import Library from './components/Library';
import Album from './components/Album';
class App extends Component {
render() {
return (
<div className="App">
<header>
<nav>
<Link to='/'>Landing</Link>
<Link to='/library'>Library</Link>
</nav>
<h1>Bloc Jams</h1>
</header>
<main>
<Route exact path="/" component={Landing} />
<Route path="/library" component={Library} />
<Route path="/album/:slug" component={Album} />
</main>
</div>
);
}
}
export default App;
Landing.js:
import React from 'react';
const Landing = () => (
<section className="landing">
<h1 className="hero-title">Turn the music up!</h1>
<section className="selling-points">
<div className="point">
<h2 className="point-title">Choose your music</h2>
<p className="point-description">The world is full of music;
why should you have to listen to music that someone else chose?</p>
</div>
<div className="point">
<h2 className="point-title">Unlimited, streaming, ad-free</h2>
<p className="point-description">No arbitrary limits. No
distractions.</p>
</div>
<div className="point">
<h2 className="point-title">Mobile enabled</h2>
<p className="point-description">Listen to your music on the
go. This streaming service is available on all mobile platforms.</p>
</div>
</section>
</section>
);
export default Landing;
Library.js:
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import albumData from './../data/albums';
class Library extends Component {
constructor(props) {
super(props);
this.state = { albums: albumData };
}
render() {
return (
<section className='library'>
{
this.state.albums.map( (album, index) =>
<Link to={`/album/${album.slug}`} key={index}>
<img src={album.albumCover} alt={album.title} />
<div>{album.title}</div>
<div>{album.artist}</div>
<div>{album.songs.length} songs</div>
</Link>
)
}
</section>
);
}
}
export default Library;
albums.js
export default [{
title: 'The Colors',
artist: 'Pablo Picasso',
releaseInfo: '1909 Spanish Records',
albumCover: '/assets/images/album_covers/01.jpg',
slug: 'the-colors',
songs: [
{ title: 'Blue', duration: '161.71', audioSrc:
'/assets/music/blue.mp3' },
{ title: 'Green', duration: '103.96', audioSrc:
'/assets/music/green.mp3' },
{ title: 'Red', duration: '268.45', audioSrc:
'/assets/music/red.mp3' },
{ title: 'Pink', duration: '153.14', audioSrc:
'/assets/music/pink.mp3' },
{ title: 'Magenta', duration: '374.22', audioSrc:
'/assets/music/magenta.mp3' }
]
}, {
title: 'The Telephone',
artist: 'Guglielmo Marconi',
releaseInfo: '1909 EM',
albumCover: '/assets/images/album_covers/02.jpg',
slug: 'the-telephone',
songs: [
{ title: 'Blue', duration: '161.71', audioSrc:
'/assets/music/blue.mp3' },
{ title: 'Green', duration: '103.96', audioSrc:
'/assets/music/green.mp3' },
{ title: 'Red', duration: '268.45', audioSrc:
'/assets/music/red.mp3' },
{ title: 'Pink', duration: '153.14', audioSrc:
'/assets/music/pink.mp3' },
{ title: 'Magenta', duration: '374.22', audioSrc:
'/assets/music/magenta.mp3' }
]
}];
Album.js:
import React, { Component } from 'react';
import albumData from './../data/albums';
class Album extends Component {
constructor(props) {
super(props);
const album = albumData.find( music => {
return album.slug === this.props.match.params.slug
});
this.state = {
album: album
};
}
render() {
return (
<section className="album">
<section id="album-info">
<img id="album-cover-art" src={this.state.album.albumCover}/>
<div className="album-details">
<h1 id="album-title">{this.state.album.title}</h1>
<h2 className="artist">{this.state.album.artist}</h2>
<div id="release-info">{this.state.album.releaseInfo} </div>
</div>
</section>
<table id="song-list">
<colgroup>
<col id="song-number-column" />
<col id="song-title-column" />
<col id="song-duration-column" />
</colgroup>
<tbody>
</tbody>
</table>
</section>
);
}
}
export default Album;
Upvotes: 1
Views: 7453
Reputation: 10370
Before passing props to <Album />
you should check inside the <Route />
for matching slug
i.e : albumData.find()
so inside App.js
before rendering <Album>
:
component={ props => {
const album = albumData.find(music =>
music.slug === props.match.params.slug
);
So your Album component Route should be like :
<Route
exact
path="/album/:slug"
component={ props => {
const album = albumData.find(music =>
music.slug === props.match.params.slug
);
return (<Album album={album} {...props}>);
}}
/>
Make sure to move albumData
inside App.js (fix the path accordingly)
import albumData from './../data/albums';
Make use of <Switch>
and move your Header logic inside another Header component instead of main App.js
import React, { Component } from 'react';
import { Route, Link , Switch } from 'react-router-dom';
import './App.css';
import Landing from './components/Landing';
import Library from './components/Library';
import Album from './components/Album';
import albumData from './../data/albums';
class App extends Component {
render() {
return (
<div className="App">
<Switch>
<Route exact path="/" component={Landing} />
<Route path="/library" component={Library} />
<Route
exact
path="/album/:slug"
component={ props => {
const album = albumData.find(music =>
music.slug === props.match.params.slug
);
return (<Album album={album} {...props}>);
}}
/>
</Switch>
</div>
);
}
}
export default App;
And now inside Your Album.js
you don't need to declare any constructor as it will be just passed as a props
to <Album >
So your Album.js should be now :
import React, { Component } from 'react';
class Album extends Component {
render() {
return (
<section className="album">
<section id="album-info">
<img id="album-cover-art" src={this.props.album.albumCover}/>
<div className="album-details">
<h1 id="album-title">{this.props.album.title}</h1>
<h2 className="artist">{this.props.album.artist}</h2>
<div id="release-info">{this.props.album.releaseInfo} </div>
</div>
</section>
<table id="song-list">
<colgroup>
<col id="song-number-column" />
<col id="song-title-column" />
<col id="song-duration-column" />
</colgroup>
<tbody>
</tbody>
</table>
</section>
);
}
}
export default Album;
Or you can make use of destructing const { releaseInfo } = this.props.album
and then this.props.album.releaseInfo
should be just releaseInfo
(You can amend this accordingly)
Upvotes: 1