Golan Kiviti
Golan Kiviti

Reputation: 4255

React Router - route inside route doesnt work

I'm new to react and I'm trying to make a simple exercise, show a list of artists that each item links to the artist page which contains the artist's albums that each of them links to the album page which contains a list of songs.

I'm having trouble with the routing, I managed to link from artist name to its page, but if I click on the album I see that the url changes but the content stays the same.

My files:

app.jsx:

import React from 'react'
import { Link } from 'react-router';

export default class App extends React.Component {

  render () {
    return (<div>
      {this.props.children}
    </div>)
  }
}

artists.jsx:

import React from 'react';
import { Link } from 'react-router';

import { getArtists } from '../stores/artists-store';

export default class Artists extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            artists: getArtists()
        };
    }
    render () {
        return (<div>
            <h1>Artists</h1>
            {this.state.artists.map((artist) =>
                <div key={artist.id}>
                    <Link to={'artists/' + artist.id}>
                        {artist.name}
                    </Link>
                </div>
            )}
        </div>);
    }
}

artist.jsx:

import React from 'react';
import { Link } from 'react-router';

import { getArtistById } from '../stores/artists-store';

export default class Artist extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            artist: getArtistById(this.props.params.id)
        };
    }
    render() {
        return (
            <div>
                <h2>{this.state.artist.name}</h2>
                {this.state.artist.albums.map((album) =>
                    <div key={album.id}>
                        <Link to={'albums/' + album.id}>
                            {album.name}
                        </Link>
                    </div>
                )}
            </div>
        );
    }
}

album.jsx:

import React from 'react'

import Song from './song';
import { getAlbumById } from '../stores/artists-store';

export default class Album extends React.Component {
    constructor(props) {
        debugger;
        super(props);
        this.state = {
            album: getAlbumById(this.props.params.id)
        };
    }

    render () {
        return (
            <div>
                <h3>{this.state.album.name}</h3>
                {this.state.album.songs.map((song) => <Song key={song.id} name={song.name}/>)}
            </div>
        )
    }
}

song.jsx:

import React from 'react'

export default class Song extends React.Component {
    render () {
        return <div>this.props.name</div>
    }
}

artists-store.js which contains the data:

export let artists = [
  { id: 1,
    name: 'Imagine Dragons',
    albums: [
      { id: 1,
        name: 'Night Visions',
        songs: [
          { id: 1, name: 'Radioactive'}
        ]},
      { id: 2,
        name: 'Smoke + Mirrors',
        songs: [
          { id: 2, Name: 'Shots'}
        ]}
    ]},
  { id: 2,
    name: 'Bastille',
    albums: [
      { id: 3,
        name: 'All This Bad Blood',
        songs: [
          { id: 3, name: 'Pompeii'}
        ]}
    ]}
];

export let nextArtistId: 3;
export let nextAlbumId : 4;
export let nextSongId : 4;

export function getArtists() { return artists }

export function getNextArtistId() { return nextArtistId }

export function getNextAlbumId() { return nextAlbumId }

export function getNextSongId() { return nextSongId }

export function getArtistById(id) {
  let artist = artists.filter((current) =>{
    if (current.id == id)
      return current;
  });

  return artist[0];
}

export function getAlbumById(id) {
    let album = artists.map((artist) =>
        artist.albums.filter((album) => {
            if (album.id == id) {
                return album;
            }
        })
    );

    return album;
}

export function addArtist(artistName) {
  artists.push({id: nextArtistId, name: artistName});
  nextArtistId++;
};

main.js:

import React from 'react';
import {render} from 'react-dom';
import { Router, Route, IndexRoute, browserHistory } from 'react-router';

import App from './Components/app';
import Artists from './Components/artists';
import Artist from './Components/artist';
import Album from './Components/album';

render(
    <Router history={browserHistory}>
        <Route path='/' component={App}>
            <IndexRoute component={Artists}/>
            <Route path='artists/:id' component={Artist}>
                <Route path='/albums/:id' component={Album}/>
            </Route>
        </Route>
    </Router>, document.getElementById('app'));

index.html:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Hello</title>
  </head>
  <body>
    <div id='app'></div>
    <script src="bundle.js"></script>
  </body>
</html>

I assume that it has to do with the routing but I can't figure out what is it.

Upvotes: 0

Views: 809

Answers (1)

QoP
QoP

Reputation: 28397

It is because /albums/:id is a nested route of artist/:id, you got two choices

A) Change the routes like this

<Route path='artists/:id' component={Artist}/>
<Route path='albums/:id' component={Album}/>

B) Keep your routes like you got them now and include {this.props.children} in your artist component since your album component is a nested route.

import React from 'react';
import { Link } from 'react-router';

import { getArtistById } from '../stores/artists-store';

    export default class Artist extends React.Component {
        constructor(props) {
            super(props);
            this.state = {
                artist: getArtistById(this.props.params.id)
            };
        }
        render() {
            return (
                <div>
                    <div className="albums">{this.props.children}</div>
                    <h2>{this.state.artist.name}</h2>
                    {this.state.artist.albums.map((album) =>
                        <div key={album.id}>
                            <Link to={'albums/' + album.id}>
                                {album.name}
                            </Link>
                        </div>
                    )}
                </div>
            );
        }
    }

Upvotes: 1

Related Questions