< Previous: Time for a Test: Clickable Usernames   Next: Time for some Basic User Interface Polish >

Making Usernames Clickable: My Solution

I hope you took the opportunity to have a go at this project by yourself, because doing so will really help cement your new learning clearly in your head. Regardless, I promised I'd walk through a solution with you, so here goes! (Note: in the unlikely even that your solution is very different to mine, you may find it easiest to adjust yours a little so you can continue following this tutorial.)

First, create a new file in the pages directory called User.js. Now give it this initial content:

src/pages/User.js

import React from 'react';
import ajax from 'superagent';

class User extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            events: []
        };
    }

    componentWillMount() {
        ajax.get(`https://api.github.com/users/${this.props.params.user}/events`)
            .end((error, response) => {
                if (!error && response) {
                    this.setState({ events: response.body });
                } else {
                    console.log(`Error fetching user data.`, error);
                }
            }
        );
    }

    render() {
        return (<div>
            <p>Content for {this.props.params.user} to go here.</p>
        </div>);
    }
}

export default User;

That is just a cut-down version of the Detail component right now. To keep things simple, I've moved the Ajax call back to componentWillMount() because we're only fetching one type of event here, and the render() method doesn't do anything yet – we'll get onto that soon enough.

Before, though, I want to update routes.js so that it sends users towards this new component ready to load. You should notice that I've used this.props.params.user twice in the code above, which means you should be able to figure out what the new route should be in routes.js:

src/routes.js

<Route path="user/:user" component={ User } />

Note: you will need to add import User from './pages/User'; to your list of imports in order for that to work.

The last thing we do before starting the work of making the User page render correctly is to update the Detail component with links on all the usernames. So, open up Detail.js for editing, and you can start by adding this to the list of imports:

src/pages/Detail.js

import { Link } from 'react-router';

You can now add a <Link> component in all three places usernames appear: renderCommits(), renderForks(), and renderPulls(). This is a pretty trivial change, but just for reference here's how I updated mine:

src/pages/Detail.js

renderCommits() {
    return this.state.commits.map((commit, index) => {
        const author = commit.author ? commit.author.login : 'Anonymous';

        return (<p key={index}>
            <Link to={ `/user/${author}` }>{author}</Link>:
            <a href={commit.html_url}>{commit.commit.message}</a>.
        </p>);
    });
}

renderForks() {
    return this.state.forks.map((fork, index) => {
        const owner = fork.owner ? fork.owner.login : 'Anonymous';

        return (<p key={index}>
            <Link to={ `/user/${owner}` }>{owner}</Link>: forked to
            <a href={fork.html_url}>{fork.html_url}</a> at {fork.created_at}.
        </p>);
    });
}

renderPulls() {
    return this.state.pulls.map((pull, index) => {
        const user = pull.user ? pull.user.login : 'Anonymous';

        return (<p key={index}>
            <Link to={ `/user/${user}` }>{user}</Link>:
            <a href={pull.html_url}>{pull.body}</a>.
        </p>);
    });
}

We now have a route to our new page, several links to it from the Detail component, plus a very basic implementation in User.js. Hopefully you had a look through an example user feed to see what data is available, and have some ideas of what you want to do.

If you want to go all out, you might want to consider having more than one render() method for the User component, just like with the Detail component, so that you can expose lots of interesting information. Here, though, I'll keep it simple, and you can add more info in your own time. We're just going to use the event type (e.g. "PushEvent"), the repository name, and the creation date.

The basic code I took from Detail does nearly all the work. In fact, all that's left is to write the render() method and we're done. Rather than use lots of paragraphs of text, I decided to show this page as a list – you're welcome to be more creative! Here's my render() method in the User page:

src/pages/User.js

render() {
    return <ul>
        {this.state.events.map((event, index) => {
            const eventType = event.type;
            const repoName = event.repo.name;
            const creationDate = event.created_at;

            return (<li key={index}>
                <strong>{repoName}</strong>: {eventType}
                at {creationDate}.
            </li>);
        })}
    </ul>;
}

As with printing forks from earlier, you might find you need to put the at {creationDate} part on the same line as the {eventType} to avoid missing whitespace.

That's it! You should now be able to start at http://localhost:8080/#/, choose a repository, click a button to select whether you want to see commits, forks, or pulls, then click a username to view their recent history – good job!

Buy the book for $10

Get the complete, unabridged Hacking with React e-book and take your learning to the next level - includes a 45-day no questions asked money back guarantee!

If this was helpful, please take a moment to tell others about Hacking with React by tweeting about it!

< Previous: Time for a Test: Clickable Usernames   Next: Time for some Basic User Interface Polish >

Copyright ©2016 Paul Hudson. Follow me: @twostraws.