-
-
Notifications
You must be signed in to change notification settings - Fork 15.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Replace universal example with async-with-routing and async-universal #1403
Closed
Closed
Changes from all commits
Commits
Show all changes
42 commits
Select commit
Hold shift + click to select a range
3ddb19f
basic universal example with react-router and react-router-redux
c8ab126
cleaning
bf0fafb
update to react-router-redux 4.x
46dd120
cleaning
6426b3f
cleaning
f7ec1a9
init
e50bcad
async-router example
0fd5f12
async-with-routing example
7393f90
cleaning
81b8006
cleaning
40f6ec6
delete universal-with-router based on counter example
25cfc5a
cleaning
41932f1
simplification of the routing
4dc3944
title update
53a594b
linting
2c42ba8
linting
d05f8d2
name and description update
0dc353f
async-universal example
30e4d80
generic index route
4033f7d
cleaning
35fcf27
generic index route
c91dccb
Layout.js removed
71d55cf
intermediate refactoring
9633ecf
cleaning
c8bfd67
move fetchdata into container
ad054bb
cleaning
a1f2d63
remove transform-class-properties
545b288
remove static keyword
a489327
missing space
d4604bb
typo
110489e
remove unused import
5b96f84
Remove hacks to alias Redux to src folder in examples
50ef70c
Per-file ESLint exceptions removed
bf3b17a
Layout.js renamed to App.js
6890c4a
Remove NoErrorsPlugin
38105ca
Remove NoErrorsPlugin
a424585
compile redux from source is needed here
6a5d6e6
App component with kind of header added
a56fcbb
indentation
2f3cad8
babel-preset-react-hmre removed
35469d4
es5 version for the sake of consistency
052c8d7
Merge https://github.com/reactjs/redux
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"presets": ["es2015", "react"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import 'babel-polyfill' | ||
import React from 'react' | ||
import { render } from 'react-dom' | ||
import { Provider } from 'react-redux' | ||
import { Router, browserHistory } from 'react-router' | ||
|
||
import configureStore from '../common/store/configureStore' | ||
import routes from '../common/routes' | ||
|
||
const initialState = window.__INITIAL_STATE__ | ||
const store = configureStore(initialState) | ||
const rootElement = document.getElementById('app') | ||
|
||
render( | ||
<Provider store={store}> | ||
<Router history={browserHistory}> | ||
{routes} | ||
</Router> | ||
</Provider>, | ||
rootElement | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import fetch from 'isomorphic-fetch' | ||
|
||
export const REQUEST_POSTS = 'REQUEST_POSTS' | ||
export const RECEIVE_POSTS = 'RECEIVE_POSTS' | ||
export const SELECT_REDDIT = 'SELECT_REDDIT' | ||
export const INVALIDATE_REDDIT = 'INVALIDATE_REDDIT' | ||
|
||
export function selectReddit(reddit) { | ||
return { | ||
type: SELECT_REDDIT, | ||
} | ||
} | ||
|
||
export function invalidateReddit(reddit) { | ||
return { | ||
type: INVALIDATE_REDDIT, | ||
} | ||
} | ||
|
||
function requestPosts(reddit) { | ||
return { | ||
type: REQUEST_POSTS, | ||
} | ||
} | ||
|
||
function receivePosts(reddit, json) { | ||
return { | ||
type: RECEIVE_POSTS, | ||
reddit: reddit, | ||
posts: json.data.children.map(child => child.data), | ||
receivedAt: Date.now() | ||
} | ||
} | ||
|
||
function fetchPosts(reddit) { | ||
return dispatch => { | ||
dispatch(requestPosts(reddit)) | ||
return fetch(`https://www.reddit.com/r/${reddit}.json`) | ||
.then(response => response.json()) | ||
.then(json => dispatch(receivePosts(reddit, json))) | ||
} | ||
} | ||
|
||
function shouldFetchPosts(state, reddit) { | ||
const posts = state.postsByReddit[reddit] | ||
if (!posts) { | ||
return true | ||
} | ||
if (posts.isFetching) { | ||
return false | ||
} | ||
return posts.didInvalidate | ||
} | ||
|
||
export function fetchPostsIfNeeded(reddit) { | ||
return (dispatch, getState) => { | ||
if (shouldFetchPosts(getState(), reddit)) { | ||
return dispatch(fetchPosts(reddit)) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import React, { Component } from 'react' | ||
|
||
export default class App extends Component { | ||
render() { | ||
return ( | ||
<div> | ||
<div> | ||
<h3>Redux async universal example</h3> | ||
<p>Code on <a href="https://github.com/reactjs/redux">Github</a></p> | ||
<hr/> | ||
</div> | ||
{this.props.children} | ||
</div> | ||
) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import React, { Component, PropTypes } from 'react' | ||
|
||
export default class Picker extends Component { | ||
render() { | ||
const { value, onChange, options } = this.props | ||
|
||
return ( | ||
<span> | ||
<h1>{(value) ? value : 'Select a subreddit below'}</h1> | ||
<select onChange={e => onChange(e.target.value)} | ||
value={value}> | ||
{options.map(option => | ||
<option value={option} key={option}> | ||
{option} | ||
</option>) | ||
} | ||
</select> | ||
</span> | ||
) | ||
} | ||
} | ||
|
||
Picker.propTypes = { | ||
options: PropTypes.arrayOf( | ||
PropTypes.string.isRequired | ||
).isRequired, | ||
value: PropTypes.string.isRequired, | ||
onChange: PropTypes.func.isRequired | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import React, { PropTypes, Component } from 'react' | ||
|
||
export default class Posts extends Component { | ||
render() { | ||
return ( | ||
<ul> | ||
{this.props.posts.map((post, i) => | ||
<li key={i}>{post.title}</li> | ||
)} | ||
</ul> | ||
) | ||
} | ||
} | ||
|
||
Posts.propTypes = { | ||
posts: PropTypes.array.isRequired | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
import React, { Component, PropTypes } from 'react' | ||
import { connect } from 'react-redux' | ||
import { selectReddit, fetchPostsIfNeeded, invalidateReddit } from '../actions' | ||
import Picker from '../components/Picker' | ||
import Posts from '../components/Posts' | ||
|
||
class Reddit extends Component { | ||
|
||
constructor(props) { | ||
super(props) | ||
this.handleChange = this.handleChange.bind(this) | ||
this.handleRefreshClick = this.handleRefreshClick.bind(this) | ||
} | ||
|
||
componentWillReceiveProps(nextProps) { | ||
const { dispatch, params } = this.props | ||
|
||
if (nextProps.params.id !== params.id) { | ||
dispatch(selectReddit(nextProps.params.id)) | ||
if (nextProps.params.id) { | ||
dispatch(fetchPostsIfNeeded(nextProps.params.id)) | ||
} | ||
} | ||
|
||
} | ||
|
||
handleChange(nextReddit) { | ||
this.context.router.push(`/${nextReddit}`) | ||
} | ||
|
||
handleRefreshClick(e) { | ||
e.preventDefault() | ||
|
||
const { dispatch, selectedReddit } = this.props | ||
dispatch(invalidateReddit(selectedReddit)) | ||
dispatch(fetchPostsIfNeeded(selectedReddit)) | ||
} | ||
|
||
render() { | ||
const { selectedReddit, posts, isFetching, lastUpdated } = this.props | ||
const isEmpty = posts.length === 0 | ||
return ( | ||
<div> | ||
<Picker value={selectedReddit} | ||
onChange={this.handleChange} | ||
options={ [ '', 'reactjs', 'frontend' ] } /> | ||
<p> | ||
{lastUpdated && | ||
<span> | ||
Last updated at {new Date(lastUpdated).toLocaleTimeString()}. | ||
{' '} | ||
</span> | ||
} | ||
{!isFetching && selectedReddit && | ||
<a href="#" | ||
onClick={this.handleRefreshClick}> | ||
Refresh | ||
</a> | ||
} | ||
</p> | ||
{isEmpty | ||
? (isFetching ? <h2>Loading...</h2> : <h2>Empty.</h2>) | ||
: <div style={{ opacity: isFetching ? 0.5 : 1 }}> | ||
<Posts posts={posts}/> | ||
</div> | ||
} | ||
</div> | ||
) | ||
} | ||
} | ||
|
||
Reddit.fetchData = (dispatch, params) => { | ||
const subreddit = params.id | ||
if (subreddit) { | ||
return Promise.all([ | ||
dispatch(selectReddit(subreddit)), | ||
dispatch(fetchPostsIfNeeded(subreddit)) | ||
]) | ||
} else { | ||
return Promise.resolve() | ||
} | ||
} | ||
|
||
Reddit.contextTypes = { | ||
router: PropTypes.object | ||
} | ||
|
||
Reddit.propTypes = { | ||
selectedReddit: PropTypes.string.isRequired, | ||
posts: PropTypes.array.isRequired, | ||
isFetching: PropTypes.bool.isRequired, | ||
lastUpdated: PropTypes.number, | ||
dispatch: PropTypes.func.isRequired | ||
} | ||
|
||
function mapStateToProps(state) { | ||
const { selectedReddit, postsByReddit } = state | ||
const { | ||
isFetching, | ||
lastUpdated, | ||
items: posts | ||
} = postsByReddit[selectedReddit] || { | ||
isFetching: false, | ||
items: [] | ||
} | ||
|
||
return { | ||
selectedReddit, | ||
posts, | ||
isFetching, | ||
lastUpdated | ||
} | ||
} | ||
|
||
export default connect(mapStateToProps)(Reddit) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import { combineReducers } from 'redux' | ||
import { | ||
SELECT_REDDIT, INVALIDATE_REDDIT, | ||
REQUEST_POSTS, RECEIVE_POSTS | ||
} from '../actions' | ||
|
||
function selectedReddit(state = '', action) { | ||
switch (action.type) { | ||
case SELECT_REDDIT: | ||
return action.reddit || '' | ||
default: | ||
return state | ||
} | ||
} | ||
|
||
function posts(state = { | ||
isFetching: false, | ||
didInvalidate: false, | ||
items: [] | ||
}, action) { | ||
switch (action.type) { | ||
case INVALIDATE_REDDIT: | ||
return Object.assign({}, state, { | ||
didInvalidate: true | ||
}) | ||
case REQUEST_POSTS: | ||
return Object.assign({}, state, { | ||
isFetching: true, | ||
didInvalidate: false | ||
}) | ||
case RECEIVE_POSTS: | ||
return Object.assign({}, state, { | ||
isFetching: false, | ||
didInvalidate: false, | ||
items: action.posts, | ||
lastUpdated: action.receivedAt | ||
}) | ||
default: | ||
return state | ||
} | ||
} | ||
|
||
function postsByReddit(state = { }, action) { | ||
switch (action.type) { | ||
case INVALIDATE_REDDIT: | ||
case RECEIVE_POSTS: | ||
case REQUEST_POSTS: | ||
return Object.assign({}, state, { | ||
[action.reddit]: posts(state[action.reddit], action) | ||
}) | ||
default: | ||
return state | ||
} | ||
} | ||
|
||
const rootReducer = combineReducers({ | ||
postsByReddit, | ||
selectedReddit | ||
}) | ||
|
||
export default rootReducer |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import React from 'react' | ||
import Route from 'react-router/lib/Route' | ||
import IndexRoute from 'react-router/lib/IndexRoute' | ||
|
||
import App from './components/App' | ||
import Reddit from './containers/Reddit' | ||
|
||
export default ( | ||
<Route path="/" component={App}> | ||
<IndexRoute component={Reddit}/> | ||
<Route path=":id" component={Reddit}/> | ||
</Route> | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { createStore, applyMiddleware } from 'redux' | ||
import thunkMiddleware from 'redux-thunk' | ||
import createLogger from 'redux-logger' | ||
import rootReducer from '../reducers' | ||
|
||
export default function configureStore(initialState) { | ||
const store = createStore( | ||
rootReducer, | ||
initialState, | ||
applyMiddleware(thunkMiddleware, createLogger()) | ||
) | ||
|
||
if (module.hot) { | ||
// Enable Webpack hot module replacement for reducers | ||
module.hot.accept('../reducers', () => { | ||
const nextRootReducer = require('../reducers').default | ||
store.replaceReducer(nextRootReducer) | ||
}) | ||
} | ||
|
||
return store | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This config is a bit weird. Routes describe component nesting structure.
Reddit
being insideReddit
doesn’t quite make sense to me. I’m not very good at router configs these days, but I think there should be a way to express this more correctly.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I get it now. You used to have
Layout
but I asked to remove it, and this is why it looks strange now. As I also write below, please addLayout
back but make it more useful. You can call itApp
instead and add a header to it that links to the source, like inreal-world
example. I believe this should be enough to use what seems to be a more correct route config (withIndexRoute
and aRoute
inside a generic app-wide route).