Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/baxtergu/react-hn


https://github.com/baxtergu/react-hn

Last synced: 26 days ago
JSON representation

Awesome Lists containing this project

README

        

React HN (Clone & Modified from: https://github.com/mking/react-hn)
===
This is a visual React tutorial. This tutorial should give you a feel for "growing" a React UI from small, modular parts. By the end of this tutorial, you will have built the [HN front page in React](https://mking.github.io/react-hn).

> Note: This tutorial covers React, Browserify, and CSS. It does not cover event handling (not needed for the HN front page), state (not needed for the HN front page), or Flux.

This tutorial has five parts:

1. [Setup](#setup)

1. [NewsItem component](#newsitem)

1. [NewsHeader component](#newsheader)

1. [NewsList component](#newslist)

1. [Display live data from the Hacker News API](#hacker-news-api)

---

Setup
---
1. Create the project directory structure.
```bash
mkdir -p hn/{build/js,css,html,img,js,json}
cd hn
```

> Note: We will be building the project from scratch. The solution in this repo is meant primarily to be a reference.

1. [Download the sample data](https://raw.githubusercontent.com/mking/react-hn/master/json/items.json) into /json.

1. Download [y18.gif](https://news.ycombinator.com/y18.gif) and [grayarrow2x.gif](https://news.ycombinator.com/grayarrow2x.gif) into /img.

1. Create /package.json.
```json
{
"name": "hn",
"version": "0.1.0",
"private": true,
"browserify": {
"transform": [
["reactify"]
]
}
}
```

1. Install Browserify, React, and tools.
```bash
# These dependencies are required for running the app.
npm install --save react jquery lodash moment

# These dependencies are required for building the app.
npm install --save-dev browserify watchify reactify

# These dependencies are globally installed command line tools.
npm install -g browserify watchify http-server
```

[Next](#newsitem)

---

NewsItem
---
1. [Display the title.](#newsitem-title)

1. [Add the domain.](#newsitem-domain)

1. [Add the subtext.](#newsitem-subtext)

1. [Add the rank and vote.](#newsitem-rank-and-vote)

[Previous](#setup) · [Next](#newsitem-title)

---

NewsItem Title
---
1. Create a new JS file: /js/NewsItem.js.
```javascript
var $ = require('jquery');
var React = require('react');

var NewsItem = React.createClass({
render: function () {
return (


{this.props.item.title}

);
}
});

module.exports = NewsItem;
```

> Note: You should be able to paste this code directly into your JS file.

1. Create a new JS file: /js/NewsItemTest.js.
```javascript
var $ = require('jquery');
var NewsItem = require('./NewsItem');
var React = require('react');

$.ajax({
url: '/json/items.json'
}).then(function (items) {
// Log the data so we can inspect it in the developer console.
console.log('items', items);
// Use a fake rank for now.
React.render(, $('#content')[0]);
});
```

> Note: This lets us develop the NewsItem component in isolation, rather than requiring it to be hooked into the full app.

1. Create a new CSS file: /css/NewsItem.css. We are following [Jacob Thornton's CSS style guide](https://medium.com/@fat/mediums-css-is-actually-pretty-fucking-good-b8e2a6c78b06).
```css
.newsItem {
color: #828282;
margin-top: 5px;
}

.newsItem-titleLink {
color: black;
font-size: 10pt;
text-decoration: none;
}
```

1. Create a new CSS file: /css/app.css.
```css
body {
font-family: Verdana, sans-serif;
}
```

1. Create a new HTML file: /html/NewsItem.html.
```html




NewsItem








```

1. Start Watchify. This compiles your React (JSX) components into ordinary JavaScript.
```bash
watchify -v -o build/js/NewsItemTest.js js/NewsItemTest.js
```

1. Start the HTTP server.
```bash
http-server -p 8888
```

1. Visit [http://localhost:8888/html/NewsItem.html](http://localhost:8888/html/NewsItem.html). You should see the following.

[Previous](#newsitem) · [Next](#newsitem-domain)

NewsItem Domain
---
1. Update the JS.
```javascript
// ...
var url = require('url');

var NewsItem = React.createClass({
// ...

getDomain: function () {
return url.parse(this.props.item.url).hostname;
},

render: function () {
return (


...

({this.getDomain()})


);
}
```

> Note: This code should be added onto the existing code in /js/NewsItem.js.

1. Update the CSS.
```css
.newsItem-domain {
font-size: 8pt;
margin-left: 5px;
}
```

> Note: This code should be added onto the existing code in /css/NewsItem.css.

1. Refresh the browser. You should see the following.

[Previous](#newsitem-title) · [Next](#newsitem-subtext)

---

NewsItem Subtext
---
1. Update the JS. Note: We are factoring out the title part into its own method.
```javascript
// ...
var moment = require('moment');

var NewsItem = React.createClass({
// ...

getCommentLink: function () {
var commentText = 'discuss';
if (this.props.item.kids && this.props.item.kids.length) {
// This only counts top-level comments.
// To get the full count, recursively get item details for this news item.
commentText = this.props.item.kids.length + ' comments';
}

return (
{commentText}
);
},

getSubtext: function () {
return (


{this.props.item.score} points by {this.props.item.by} {moment.utc(this.props.item.time * 1000).fromNow()} | {this.getCommentLink()}

);
},

getTitle: function () {
return (


...

);
},

render: function () {
return (


{this.getTitle()}
{this.getSubtext()}

);
}
```

1. Update the CSS.
```css
.newsItem-subtext {
font-size: 7pt;
}

.newsItem-subtext > a {
color: #828282;
text-decoration: none;
}

.newsItem-subtext > a:hover {
text-decoration: underline;
}
```

1. Refresh the browser. You should see the following.

[Previous](#newsitem-domain) · [Next](#newsitem-rank-and-vote)

---

NewsItem Rank and Vote
---
1. Update the JS.
```javascript
var NewsItem = React.createClass({
// ...

getRank: function () {
return (


{this.props.rank}.

);
},

getVote: function () {
return (






);
},

render: function () {
return (


{this.getRank()}
{this.getVote()}

{this.getTitle()}
{this.getSubtext()}


);
}
```

1. Update the CSS.
```css
.newsItem {
/* ... */
align-items: baseline;
display: flex;
}

.newsItem-itemText {
flex-grow: 1;
}

.newsItem-rank {
flex-basis: 25px;
font-size: 10pt;
text-align: right;
}

.newsItem-vote {
flex-basis: 15px;
text-align: center;
}
```

1. Refresh the browser. You should see the following.

You have now implemented an HN news item in React.

[Previous](#newsitem-subtext) · [Next](#newsheader)

---

NewsHeader
---
1. [Display the logo and title.](#newsheader-logo-and-title)

1. [Add the nav links.](#newsheader-nav)

1. [Add the login link.](#newsheader-login)

[Previous](#newsitem-rank-and-vote) · [Next](#newsheader-logo-and-title)

---

NewsHeader Logo and Title
---
1. Create a new JS file: /js/NewsHeader.js.
```javascript
var $ = require('jquery');
var React = require('react');

var NewsHeader = React.createClass({
getLogo: function () {
return (




);
},

getTitle: function () {
return (


Hacker News

);
},

render: function () {
return (


{this.getLogo()}
{this.getTitle()}

);
}
});

module.exports = NewsHeader;
```

1. Create a new JS file: /js/NewsHeaderTest.js.
```javascript
var $ = require('jquery');
var NewsHeader = require('./NewsHeader');
var React = require('react');

React.render(, $('#content')[0]);
```

1. Create a new CSS file: /css/NewsHeader.css.
```css
.newsHeader {
align-items: center;
background: #ff6600;
color: black;
display: flex;
font-size: 10pt;
padding: 2px;
}

.newsHeader-logo {
border: 1px solid white;
flex-basis: 18px;
height: 18px;
}

.newsHeader-textLink {
color: black;
text-decoration: none;
}

.newsHeader-title {
font-weight: bold;
margin-left: 4px;
}
```

1. Create a new HTML file: /html/NewsHeader.html.
```html




NewsHeader








```

1. Start Watchify.
```bash
watchify -v -o build/js/NewsHeaderTest.js js/NewsHeaderTest.js
```

1. Start the HTTP server if necessary.
```bash
http-server -p 8888
```

1. Visit [http://localhost:8888/html/NewsHeader.html](http://localhost:8888/html/NewsHeader.html). You should see the following.

[Previous](#newsheader) · [Next](#newsheader-nav)

---

NewsHeader Nav
---
1. Update the JS.
```javascript
// ...
var _ = require('lodash');

var NewsHeader = React.createClass({
// ...

getNav: function () {
var navLinks = [
{
name: 'new',
url: 'newest'
},
{
name: 'comments',
url: 'newcomments'
},
{
name: 'show',
url: 'show'
},
{
name: 'ask',
url: 'ask'
},
{
name: 'jobs',
url: 'jobs'
},
{
name: 'submit',
url: 'submit'
}
];

return (


{_(navLinks).map(function (navLink) {
return (

{navLink.name}

);
}).value()}

);
},

render: function () {
return (


...
{this.getNav()}

);
}
```

1. Update the CSS.
```css
.newsHeader-nav {
flex-grow: 1;
margin-left: 10px;
}

.newsHeader-navLink:not(:first-child)::before {
content: ' | ';
}
```

1. Refresh the browser. You should see the following.

[Previous](#newsheader-logo-and-title) · [Next](#newsheader-login)

---

NewsHeader Login
---
1. Update the JS.
```javascript
var NewsHeader = React.createClass({
// ...

getLogin: function () {
return (


login

);
},

render: function () {
return (


...
{this.getLogin()}

);
}
```

1. Update the CSS.
```css
.newsHeader-login {
margin-right: 5px;
}
```

1. Refresh the browser. You should see the following.

You have now implemented the HN header in React.

[Previous](#newsheader-nav) · [Next](#newslist)

---

NewsList
---
1. [Display the header and items.](#newslist-header-and-items)

1. [Add the more link.](#newslist-more)

[Previous](#newsheader-login) · [Next](#newslist-header-and-items)

---

NewsList Header and Items
---
1. Create a new JS file: /js/NewsList.js.
```javascript
var _ = require('lodash');
var NewsHeader = require('./NewsHeader');
var NewsItem = require('./NewsItem');
var React = require('react');

var NewsList = React.createClass({
render: function () {
return (




{_(this.props.items).map(function (item, index) {
return ;
}.bind(this)).value()}


);
}
});

module.exports = NewsList;
```

1. Create a new JS file: /js/NewsListTest.js.
```javascript
var $ = require('jquery');
var NewsList = require('./NewsList');
var React = require('react');

$.ajax({
url: '/json/items.json'
}).then(function (items) {
React.render(, $('#content')[0]);
});
```

1. Create a new CSS file: /css/NewsList.css.
```css
.newsList {
background: #f6f6ef;
margin-left: auto;
margin-right: auto;
width: 85%;
}
```

1. Create a new HTML file: /html/NewsList.html.
```html




NewsList










```

1. Start Watchify.
```bash
watchify -v -o build/js/NewsListTest.js js/NewsListTest.js
```

1. Start the HTTP server if necessary.
```bash
http-server -p 8888
```

1. Visit [http://localhost:8888/html/NewsList.html](http://localhost:8888/html/NewsList.html). You should see the following.

[Previous](#newslist) · [Next](#newslist-more)

---

NewsList More
---
1. Update the JS.
```javascript
var NewsList = React.createClass({
// ...

getMore: function () {
return (


More

);
},

render: function () {
return (


...
{this.getMore()}

);
}
```

1. Update the CSS.
```css
.newsList-more {
margin-left: 40px; /* matches NewsItem rank and vote */
margin-top: 10px;
padding-bottom: 10px;
}

.newsList-moreLink {
color: black;
font-size: 10pt;
text-decoration: none;
}
```

1. Refresh the browser. You should see the following.

You have now implemented the HN item list in React.

[Previous](#newslist-header-and-items) · [Next](#hacker-news-api)

---

Hacker News API
---
1. Create a new JS file: /js/app.js.
```javascript
var _ = require('lodash');
var $ = require('jquery');
var NewsList = require('./NewsList');
var React = require('react');

// Get the top item ids
$.ajax({
url: 'https://hacker-news.firebaseio.com/v0/topstories.json',
dataType: 'json'
}).then(function (stories) {
// Get the item details in parallel
var detailDeferreds = _(stories.slice(0, 30)).map(function (itemId) {
return $.ajax({
url: 'https://hacker-news.firebaseio.com/v0/item/' + itemId + '.json',
dataType: 'json'
});
}).value();
return $.when.apply($, detailDeferreds);
}).then(function () {
// Extract the response JSON
var items = _(arguments).map(function (argument) {
return argument[0];
}).value();

// Render the items
React.render(, $('#content')[0]);
});

```

1. Create a new HTML file: /html/app.html.
```html




Hacker News










```

1. Start Watchify.
```bash
watchify -v -o build/js/app.js js/app.js
```

1. Start the HTTP server if necessary.
```bash
http-server -p 8888
```

1. Visit [http://localhost:8888/html/app.html](http://localhost:8888/html/app.html).

You have now implemented the [HN front page](https://news.ycombinator.com) in React.

[Previous](#newslist-more)