Skip to content

Commit 8845b0b

Browse files
committed
modify example to use react-redux-controller
1 parent 14b60b6 commit 8845b0b

File tree

14 files changed

+186
-329
lines changed

14 files changed

+186
-329
lines changed

example/.babelrc

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,16 @@
11
{
2-
"stage": 2,
2+
"presets": ["react", "es2015"],
33
"env": {
44
"development": {
55
"plugins": [
6-
"react-transform"
7-
],
8-
"extra": {
9-
"react-transform": {
6+
["react-transform", {
107
"transforms": [{
118
"transform": "react-transform-hmr",
129
"imports": ["react"],
13-
"locals": ["module"]
10+
"locals": ["module"]
1411
}]
15-
}
16-
}
12+
}]
13+
]
1714
}
1815
}
1916
}

example/actions/index.js

Lines changed: 4 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import fetch from 'isomorphic-fetch'
2-
31
export const REQUEST_POSTS = 'REQUEST_POSTS'
42
export const RECEIVE_POSTS = 'RECEIVE_POSTS'
53
export const SELECT_REDDIT = 'SELECT_REDDIT'
@@ -19,46 +17,18 @@ export function invalidateReddit(reddit) {
1917
}
2018
}
2119

22-
function requestPosts(reddit) {
20+
export function requestPosts(reddit) {
2321
return {
2422
type: REQUEST_POSTS,
2523
reddit
2624
}
2725
}
2826

29-
function receivePosts(reddit, json) {
27+
export function receivePosts(reddit, posts) {
3028
return {
3129
type: RECEIVE_POSTS,
32-
reddit: reddit,
33-
posts: json.data.children.map(child => child.data),
30+
reddit,
31+
posts,
3432
receivedAt: Date.now()
3533
}
3634
}
37-
38-
function fetchPosts(reddit) {
39-
return dispatch => {
40-
dispatch(requestPosts(reddit))
41-
return fetch(`http://www.reddit.com/r/${reddit}.json`)
42-
.then(response => response.json())
43-
.then(json => dispatch(receivePosts(reddit, json)))
44-
}
45-
}
46-
47-
function shouldFetchPosts(state, reddit) {
48-
const posts = state.postsByReddit[reddit]
49-
if (!posts) {
50-
return true
51-
}
52-
if (posts.isFetching) {
53-
return false
54-
}
55-
return posts.didInvalidate
56-
}
57-
58-
export function fetchPostsIfNeeded(reddit) {
59-
return (dispatch, getState) => {
60-
if (shouldFetchPosts(getState(), reddit)) {
61-
return dispatch(fetchPosts(reddit))
62-
}
63-
}
64-
}

example/components/Layout.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import React, { PropTypes } from 'react'
2+
import Picker from '../components/Picker'
3+
import Posts from '../components/Posts'
4+
5+
export default function Layout(_, { posts, isFetching, lastUpdated, onRefresh }) {
6+
return (
7+
<div>
8+
<Picker options={[ 'reactjs', 'frontend' ]} />
9+
<p>
10+
{lastUpdated &&
11+
<span>
12+
Last updated at {new Date(lastUpdated).toLocaleTimeString()}.
13+
{' '}
14+
</span>
15+
}
16+
{!isFetching &&
17+
<a href="#"
18+
onClick={ e => { e.preventDefault(); onRefresh() } }>
19+
Refresh
20+
</a>
21+
}
22+
</p>
23+
{isFetching && posts.length === 0 &&
24+
<h2>Loading...</h2>
25+
}
26+
{!isFetching && posts.length === 0 &&
27+
<h2>Empty.</h2>
28+
}
29+
{posts.length > 0 &&
30+
<div style={{ opacity: isFetching ? 0.5 : 1 }}>
31+
<Posts />
32+
</div>
33+
}
34+
</div>
35+
)
36+
}
37+
38+
Layout.contextTypes = {
39+
posts: PropTypes.array.isRequired,
40+
isFetching: PropTypes.bool.isRequired,
41+
lastUpdated: PropTypes.number,
42+
onRefresh: PropTypes.func.isRequired
43+
}

example/components/Picker.js

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,28 @@
1-
import React, { Component, PropTypes } from 'react'
1+
import React, { PropTypes } from 'react'
22

3-
export default class Picker extends Component {
4-
render() {
5-
const { value, onChange, options } = this.props
6-
7-
return (
8-
<span>
9-
<h1>{value}</h1>
10-
<select onChange={e => onChange(e.target.value)}
11-
value={value}>
12-
{options.map(option =>
13-
<option value={option} key={option}>
14-
{option}
15-
</option>)
16-
}
17-
</select>
18-
</span>
19-
)
20-
}
3+
export default function Picker({ options }, { selectedReddit, onSelectReddit }) {
4+
return (
5+
<span>
6+
<h1>{ selectedReddit }</h1>
7+
<select onChange={ e => onSelectReddit(e.target.value) }
8+
value={ selectedReddit }>
9+
{ options.map(option =>
10+
<option value={ option } key={ option }>
11+
{ option }
12+
</option>)
13+
}
14+
</select>
15+
</span>
16+
)
2117
}
2218

2319
Picker.propTypes = {
2420
options: PropTypes.arrayOf(
2521
PropTypes.string.isRequired
26-
).isRequired,
27-
value: PropTypes.string.isRequired,
28-
onChange: PropTypes.func.isRequired
22+
).isRequired
23+
}
24+
25+
Picker.contextTypes = {
26+
selectedReddit: PropTypes.string.isRequired,
27+
onSelectReddit: PropTypes.func.isRequired
2928
}

example/components/Posts.js

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
1-
import React, { PropTypes, Component } from 'react'
1+
import React, { PropTypes } from 'react'
22

3-
export default class Posts extends Component {
4-
render() {
5-
return (
6-
<ul>
7-
{this.props.posts.map((post, i) =>
8-
<li key={i}>{post.title}</li>
9-
)}
10-
</ul>
11-
)
12-
}
3+
export default function Posts(_, { posts }) {
4+
return (
5+
<ul>
6+
{ posts.map((post, i) =>
7+
<li key={ i }>{ post.title }</li>
8+
)}
9+
</ul>
10+
)
1311
}
1412

15-
Posts.propTypes = {
13+
Posts.contextTypes = {
1614
posts: PropTypes.array.isRequired
1715
}

example/containers/App.js

Lines changed: 0 additions & 102 deletions
This file was deleted.

example/controllers/App.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import 'babel-polyfill'
2+
import fetch from 'isomorphic-fetch'
3+
import React, { Component, PropTypes } from 'react'
4+
import { controller, getProps } from 'react-redux-controller'
5+
import * as actions from '../actions'
6+
import * as selectors from '../selectors'
7+
import Layout from '../components/Layout'
8+
9+
const controllerGenerators = {
10+
*initialize() {
11+
const { selectedReddit } = yield getProps
12+
13+
yield this.fetchPostsIfNeeded(selectedReddit)
14+
},
15+
16+
*onSelectReddit(nextReddit) {
17+
const { dispatch, selectedReddit } = yield getProps
18+
19+
dispatch(actions.selectReddit(nextReddit))
20+
21+
if (nextReddit !== selectedReddit) {
22+
yield this.fetchPostsIfNeeded(nextReddit)
23+
}
24+
},
25+
26+
*onRefresh() {
27+
const { dispatch, selectedReddit } = yield getProps
28+
29+
dispatch(actions.invalidateReddit(selectedReddit))
30+
yield this.fetchPostsIfNeeded(selectedReddit)
31+
},
32+
33+
*fetchPostsIfNeeded(reddit) {
34+
const { postsByReddit } = yield getProps
35+
36+
const posts = postsByReddit[reddit]
37+
if (!posts || !posts.isFetching || posts.didInvalidate) {
38+
yield this.fetchPosts(reddit)
39+
}
40+
},
41+
42+
*fetchPosts(reddit) {
43+
const { dispatch } = yield getProps
44+
45+
dispatch(actions.requestPosts(reddit))
46+
const response = yield fetch(`http://www.reddit.com/r/${reddit}.json`)
47+
const responseJson = yield response.json()
48+
const newPosts = responseJson.data.children.map(child => child.data)
49+
dispatch(actions.receivePosts(reddit, newPosts))
50+
}
51+
}
52+
53+
export default controller(Layout, controllerGenerators, selectors)

example/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import 'babel-core/polyfill'
1+
import 'babel-polyfill'
22
import React from 'react'
33
import { render } from 'react-dom'
44
import { Provider } from 'react-redux'
5-
import App from './containers/App'
5+
import App from './controllers/App'
66
import configureStore from './store/configureStore'
77

88
const store = configureStore()

0 commit comments

Comments
 (0)