Skip to content

Commit

Permalink
Rewrite reducing boilerplate
Browse files Browse the repository at this point in the history
  • Loading branch information
gaearon committed May 5, 2015
1 parent 0ecbdfd commit fbdef56
Show file tree
Hide file tree
Showing 31 changed files with 488 additions and 605 deletions.
16 changes: 6 additions & 10 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"ecmaFeatures": {
"jsx": true
"jsx": true,
"modules": true
},
"env": {
"browser": true,
Expand Down Expand Up @@ -29,16 +30,11 @@
"react/self-closing-comp": 2,
"react/wrap-multilines": 2,
"quotes": [2, "single"],
"space-before-function-parentheses": [2, "never"],
"space-in-brackets": [2, "always", {
"singleValue": false,
"objectsInArrays": false,
"arraysInArrays": false,
"arraysInObjects": true,
"objectsInObjects": true,
"propertyName": false
"space-before-function-paren": [2, {
"anonymous": "always",
"named": "never"
}],
"strict": 2,
"strict": [2, "global"]
},
"plugins": [
"react"
Expand Down
3 changes: 2 additions & 1 deletion dist/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<head>
</head>
<body>
<div id='root'></div>
<script src="bundle.js"></script>
</body>
<script src="bundle.js"></script>
</html>
3 changes: 2 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<head>
</head>
<body>
<div id='root'></div>
<script src="/scripts/bundle.js"></script>
</body>
<script src="/scripts/bundle.js"></script>
</html>
11 changes: 8 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,24 @@
"description": "A sample app featuring Flux and React Router",
"dependencies": {
"babel-runtime": "^5.1.10",
"core-js": "^0.9.6",
"flux": "^2.0.1",
"humps": "0.0.1",
"invariant": "^2.0.0",
"keymirror": "^0.1.1",
"normalizr": "^0.1.2",
"react": "^0.13.1",
"react": "^0.13.2",
"react-document-title": "^1.0.0",
"react-router": "^0.13.2",
"superagent": "^1.2.0",
"react-pure-render": "^1.0.1",
"react-router": "^0.13.3",
"selectn": "^0.9.6",
"underscore": "^1.8.2",
"whatwg-fetch": "^0.7.0"
},
"devDependencies": {
"babel-core": "^5.1.10",
"babel-loader": "^5.0.0",
"eslint": "^0.20.0",
"react-hot-loader": "^1.1.5",
"webpack": "^1.8.4",
"webpack-dev-server": "^1.8.0"
Expand Down
7 changes: 2 additions & 5 deletions scripts/App.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
'use strict';

import React, { PropTypes } from 'react';
import Explore from './components/Explore';
import DocumentTitle from 'react-document-title';
import { RouteHandler } from 'react-router';

export default class App extends React.Component {

export default class App {
static propTypes = {
params: PropTypes.object.isRequired,
query: PropTypes.object.isRequired
}
};

render() {
return (
Expand Down
32 changes: 27 additions & 5 deletions scripts/dispatcher/AppDispatcher.js → scripts/AppDispatcher.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,27 @@
'use strict';

import { Dispatcher } from 'flux';

class AppDispatcher extends Dispatcher {
dispatch(action) {
/**
* Dispatches three actions for an async operation represented by promise.
*/
dispatchAsync(promise, types, action = {}) {
const { request, success, failure } = types;

this.dispatch(request, action);
promise.then(
response => this.dispatch(success, { ...action, response }),
error => this.dispatch(failure, { ...action, error })
);
}

/**
* Dispatches a single action.
*/
dispatch(type, action = {}) {
if (!type) {
throw new Error('You forgot to specify type.');
}

// In production, thanks to DefinePlugin in webpack.config.production.js,
// this comparison will turn `false`, and UglifyJS will cut logging out
// as part of dead code elimination.
Expand All @@ -12,13 +30,17 @@ class AppDispatcher extends Dispatcher {
// All data that flows into our application comes in form of actions.
// Actions are just plain JavaScript objects describing “what happened”.
// Think of them as newspapers.
console.log(action.type, action);
if (action.error) {
console.error(type, action);
} else {
console.log(type, action);
}
}

// Generally, inheritance and super() calls are a terrible idea,
// but we're only going one level deep here so it's not a big issue.
// Try to avoid it though!
super.dispatch(action);
super.dispatch({ type, ...action });
}

// Some Flux examples have methods like `handleViewAction`
Expand Down
70 changes: 32 additions & 38 deletions scripts/actions/RepoActionCreators.js
Original file line number Diff line number Diff line change
@@ -1,45 +1,39 @@
'use strict';

import AppDispatcher from '../dispatcher/AppDispatcher';
import { dispatchAsync } from '../AppDispatcher';
import ActionTypes from '../constants/ActionTypes';
import RepoAPI from '../api/RepoAPI';
import * as RepoAPI from '../api/RepoAPI';
import StarredReposByUserStore from '../stores/StarredReposByUserStore';
import RepoStore from '../stores/RepoStore';

export default {
requestRepo(fullName, fields) {
if (RepoStore.contains(fullName, fields)) {
return;
}

// Although this action is currently not handled by any store,
// it is fired for consistency. You might want to use it later,
// e.g. to show a spinner or have a more detailed log.

AppDispatcher.dispatch({
type: ActionTypes.REQUEST_REPO,
fullName
});

RepoAPI.requestRepo(fullName);
},

requestStarredReposPage(login, isInitialRequest) {
if (StarredReposByUserStore.isExpectingPage(login) ||
StarredReposByUserStore.isLastPage(login)) {
return;
}

if (isInitialRequest && StarredReposByUserStore.getPageCount(login) > 0) {
return;
}
export function requestRepo(fullName, fields) {
// Exit early if we know about this repo
if (RepoStore.contains(fullName, fields)) {
return;
}

AppDispatcher.dispatch({
type: ActionTypes.REQUEST_STARRED_REPOS_PAGE,
login
});
dispatchAsync(RepoAPI.getRepo(fullName), {
request: ActionTypes.REQUEST_REPO,
success: ActionTypes.REQUEST_REPO_SUCCESS,
failure: ActionTypes.REQUEST_REPO_ERROR
}, { fullName });
}

export function requestStarredReposPage(login, isInitialRequest) {
// Exit early if already fetching, or if there is nothing to fetch.
if (StarredReposByUserStore.isExpectingPage(login) ||
StarredReposByUserStore.isLastPage(login)) {
return;
}

const nextPageUrl = StarredReposByUserStore.getNextPageUrl(login);
RepoAPI.requestStarredReposPage(login, nextPageUrl);
// Ignore first page request when component is mounting if we already
// loaded at least one page before. This gives us instant Back button.
if (isInitialRequest && StarredReposByUserStore.getPageCount(login) > 0) {
return;
}
};

const nextPageUrl = StarredReposByUserStore.getNextPageUrl(login);
dispatchAsync(RepoAPI.getStarredReposPage(login, nextPageUrl), {
request: ActionTypes.REQUEST_STARRED_REPOS_PAGE,
success: ActionTypes.REQUEST_STARRED_REPOS_PAGE_SUCCESS,
failure: ActionTypes.REQUEST_STARRED_REPOS_PAGE_ERROR
}, { login });
}
38 changes: 0 additions & 38 deletions scripts/actions/RepoServerActionCreators.js

This file was deleted.

70 changes: 32 additions & 38 deletions scripts/actions/UserActionCreators.js
Original file line number Diff line number Diff line change
@@ -1,45 +1,39 @@
'use strict';

import AppDispatcher from '../dispatcher/AppDispatcher';
import { dispatchAsync } from '../AppDispatcher';
import ActionTypes from '../constants/ActionTypes';
import UserAPI from '../api/UserAPI';
import * as UserAPI from '../api/UserAPI';
import UserStore from '../stores/UserStore';
import StargazersByRepoStore from '../stores/StargazersByRepoStore';

export default {
requestUser(login, fields) {
if (UserStore.contains(login, fields)) {
return;
}

// Although this action is currently not handled by any store,
// it is fired for consistency. You might want to use it later,
// e.g. to show a spinner or have a more detailed log.

AppDispatcher.dispatch({
type: ActionTypes.REQUEST_USER,
login
});

UserAPI.requestUser(login);
},

requestStargazerPage(fullName, isInitialRequest) {
if (StargazersByRepoStore.isExpectingPage(fullName) ||
StargazersByRepoStore.isLastPage(fullName)) {
return;
}

if (isInitialRequest && StargazersByRepoStore.getPageCount(fullName) > 0) {
return;
}
export function requestUser(login, fields) {
// Exit early if we know enough about this user
if (UserStore.contains(login, fields)) {
return;
}

AppDispatcher.dispatch({
type: ActionTypes.REQUEST_STARGAZER_PAGE,
fullName
});
dispatchAsync(UserAPI.getUser(login), {
request: ActionTypes.REQUEST_USER,
success: ActionTypes.REQUEST_USER_SUCCESS,
failure: ActionTypes.REQUEST_USER_ERROR
}, { login });
}

export function requestStargazerPage(fullName, isInitialRequest) {
// Exit early if already fetching, or if there is nothing to fetch.
if (StargazersByRepoStore.isExpectingPage(fullName) ||
StargazersByRepoStore.isLastPage(fullName)) {
return;
}

const nextPageUrl = StargazersByRepoStore.getNextPageUrl(fullName);
UserAPI.requestStargazerPage(fullName, nextPageUrl);
// Ignore first page request when component is mounting if we already
// loaded at least one page before. This gives us instant Back button.
if (isInitialRequest && StargazersByRepoStore.getPageCount(fullName) > 0) {
return;
}
};

const nextPageUrl = StargazersByRepoStore.getNextPageUrl(fullName);
dispatchAsync(UserAPI.getStargazerPage(fullName, nextPageUrl), {
request: ActionTypes.REQUEST_STARGAZER_PAGE,
success: ActionTypes.REQUEST_STARGAZER_PAGE_SUCCESS,
failure: ActionTypes.REQUEST_STARGAZER_PAGE_ERROR
}, { fullName });
}
38 changes: 0 additions & 38 deletions scripts/actions/UserServerActionCreators.js

This file was deleted.

Loading

0 comments on commit fbdef56

Please sign in to comment.