├── .gitignore
├── README.md
├── package.json
├── public
├── favicon.ico
└── index.html
└── src
├── components
├── App.jsx
├── Search.jsx
└── User.jsx
├── index.css
└── index.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 |
12 | # misc
13 | .DS_Store
14 | .env
15 | npm-debug.log*
16 | yarn-debug.log*
17 | yarn-error.log*
18 |
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # React + GitHub API project
2 |
3 | In this project, we're going to take a small, existing React application and add new features to it.
4 |
5 | Here's what the application will look like once you are done:
6 |
7 | 
8 |
9 | The code you are given for the project implements the search form and the loading of basic user info. You'll have to do all the rest.
10 |
11 | Let's take a look at the code that's already there. Many of the starter files should already be familiar to you if you completed [the previous workshop](https://github.com/ziad-saab/react-intro-workshop).
12 |
13 | * `package.json`: Configuration file for NPM, contains dependencies and project metadata
14 | * `.gitignore`: Files that should be ignored by Git. `node_modules` can always be regenerated
15 | * `public/index.html`: File that gets served thru Webpack after having been filled in
16 | * `src/index.js`: This file is the entry point for the app. It puts our app on the screen!
17 | * `src/components/*`: All the components of our application.
18 | * `src/index.css`: The styles for our app. Check it out to see how your starter app is being styled, and add to it to complete the project. Notice that we don't `` this CSS from the index? How does this work?? Make sure you understand!!!
19 |
20 | **To get started coding on this project, remember the following steps**:
21 |
22 | 1. `npm install` the first time you clone this repo
23 | 2. `npm start` anytime you want to start developing. This will watch your JS files and re-run webpack when there are changes
24 | 3. Start coding!
25 |
26 | In `index.js` we have the following route structure:
27 |
28 | ```javascript
29 |
30 |
31 |
32 |
33 | ```
34 |
35 | The top route says to load the `App` component. Looking at the code of `App.jsx`, you'll see that its `render` method outputs `{this.props.children}`. If the URL happens to be only `/`, then React Router will render an `` instance, and will pass it a `` as its child. If the route happens to be `/user/:username`, React Router will display `` but will pass it `` as a child.
36 |
37 | When the `Search` component is displayed, it has a form and a button. When the form is submitted, we use React Router's `browserHistory` to **programmatically change the URL**. Look at the `Search`'s `_handleSubmit` method to see how that happens.
38 |
39 | Once we navigate to the new URL, React Router will render a `User` component. Looking at the `componentDidMount` method of the `User`, you'll see that it does an AJAX call using `this.props.params.username`. The reason why it has access to this prop is because the Router passed it when it mounted the component.
40 |
41 | The AJAX call is made to `https://api.github.com/users/{USERNAME}` and returns the following information:
42 |
43 | ```json
44 | {
45 | "login": "gaearon",
46 | "id": 810438,
47 | "avatar_url": "https://avatars.githubusercontent.com/u/810438?v=3",
48 | "gravatar_id": "",
49 | "url": "https://api.github.com/users/gaearon",
50 | "html_url": "https://github.com/gaearon",
51 | "followers_url": "https://api.github.com/users/gaearon/followers",
52 | "following_url": "https://api.github.com/users/gaearon/following{/other_user}",
53 | "gists_url": "https://api.github.com/users/gaearon/gists{/gist_id}",
54 | "starred_url": "https://api.github.com/users/gaearon/starred{/owner}{/repo}",
55 | "subscriptions_url": "https://api.github.com/users/gaearon/subscriptions",
56 | "organizations_url": "https://api.github.com/users/gaearon/orgs",
57 | "repos_url": "https://api.github.com/users/gaearon/repos",
58 | "events_url": "https://api.github.com/users/gaearon/events{/privacy}",
59 | "received_events_url": "https://api.github.com/users/gaearon/received_events",
60 | "type": "User",
61 | "site_admin": false,
62 | "name": "Dan Abramov",
63 | "company": "Facebook",
64 | "blog": "http://twitter.com/dan_abramov",
65 | "location": "London, UK",
66 | "email": "dan.abramov@me.com",
67 | "hireable": null,
68 | "bio": "Created: Redux, React Hot Loader, React DnD. Now helping make @reactjs better at @facebook.",
69 | "public_repos": 176,
70 | "public_gists": 48,
71 | "followers": 10338,
72 | "following": 171,
73 | "created_at": "2011-05-25T18:18:31Z",
74 | "updated_at": "2016-07-28T14:41:02Z"
75 | }
76 | ```
77 | [GitHub API documentation for Users](https://developer.github.com/v3/users/)
78 |
79 | In the `render` method of the `User` component, we are displaying the user info based on the received result, and we have three links that don't lead anywhere for the moment:
80 |
81 | 
82 |
83 | If you click on followers, notice that the URL of the page changes to `/users/:username/followers`. If you have your dev tools open, React Router will give you an error message telling you that this route does not exist.
84 |
85 | **The goal of this workshop** is to implement the three links above. To do this, we'll start by implementing the followers page together with step by step instructions. Then, your job will be to implement the two remaining screens and fix any bugs.
86 |
87 | ## Implementing the Followers page
88 | When clicking on the followers link in the UI, notice that the URL changes to `/user/:username/followers`. Currently this results in a "not found" route. Let's fix this.
89 |
90 | 
91 |
92 | ### Step 1: adding the route
93 | In `index.js`, you currently have your user route setup like this:
94 |
95 | ```javascript
96 |
97 | ```
98 |
99 | Let's change it to a route with a nested route
100 |
101 | ```javascript
102 |
103 |
104 |
105 | ```
106 |
107 | For this to do anything, we first have to implement the `Followers` component.
108 |
109 | ### Step 2: adding the `Followers` component
110 | Create a component called `Followers`. Since this component is also a route component, it will receive the same `this.props.params.username`. In this component, we're eventually going to do an AJAX call to grab the followers of the user.
111 |
112 | For the moment, create the component only with a `render` function. In there, use your props to return the following:
113 |
114 | ```html
115 |
116 |
Followers of USERNAME
117 |
118 | ```
119 |
120 | ### Step 3: displaying the nested component inside its parent
121 | When the URL changes to `followers`, we want to display the followers alongside the current `User` component. **This is why we are nesting the followers route inside the user route.**
122 |
123 | To reflect this nesting in our tree of components, we have to add a `{this.props.children}` output to our `User` component.
124 |
125 | Modify the `User` component to make it display its children just before the closing `` in the `render` method.
126 |
127 | When this is done, go back to your browser. Search for a user, and click on FOLLOWERS. The followers component should be displayed below the user info.
128 |
129 | ### Step 4: loading GitHub data in the `Followers` component:
130 | We want to load the followers of the current user as soon as the `Followers` component is mounted in the DOM. In the `componentDidMount` of `Followers`, use `fetch` to make a request to GitHub's API for the followers. Simply add `/followers` to the GitHub API URL for the user e.g. https://api.github.com/users/ziad-saab/followers
131 |
132 | In the callback to your AJAX request, use `setState` to set a `followers` state on your component.
133 |
134 | ### Step 5: displaying the followers data in the `Followers` component:
135 | Using the `this.state.followers` in your `render` method, display the followers that you receive from GitHub. We'll do this in a few steps.
136 |
137 | 1. Create a new pure component called `GithubUser`. It should receive a `user` prop, and use its `avatar_url` and `login` properties to display one GitHub user. The whole display should link back to that user's page in your app, using React Router's `Link` component. Here's what a sample output of your `GithubUser` component should look like:
138 |
139 | ```javascript
140 |
141 |
142 | ziad-saab
143 |
144 | ```
145 |
146 | And here's a visual example of four `GithubUser` instances (you can use `vertical-align` in your CSS to align the image and the name):
147 |
148 | 
149 |
150 | 2. In `Followers`, import your `GithubUser` component.
151 | 3. In the `render` method of `Followers`, use `map` to take the array at `this.state.followers`, and map it to an array of `` elements, passing the `user` prop. The code of `Followers`' `render` method should look like this:
152 |
153 | ```javascript
154 | if (!this.state.followers) {
155 | return
LOADING FOLLOWERS...
156 | }
157 |
158 | return (
159 |
160 |
Followers of {this.props.params.username}
161 |
162 | {this.state.followers.map(/* INSERT CODE HERE TO RETURN A NEW */)}
163 |