Skip to content

Commit 6d0107e

Browse files
committed
Merge pull request #195 from gaearon/breaking-changes-1.0
Breaking API changes for 1.0
2 parents 0b5ca2b + fd7f884 commit 6d0107e

File tree

155 files changed

+4064
-1636
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

155 files changed

+4064
-1636
lines changed

.eslintrc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,16 @@
66
"node": true
77
},
88
"rules": {
9+
"valid-jsdoc": 2,
10+
911
"react/jsx-uses-react": 2,
1012
"react/jsx-uses-vars": 2,
1113
"react/react-in-jsx-scope": 2,
1214

15+
// Disable until Flow supports let and const
16+
"no-var": 0,
17+
"vars-on-top": 0,
18+
1319
//Temporarirly disabled due to a possible bug in babel-eslint (todomvc example)
1420
"block-scoped-var": 0,
1521
// Temporarily disabled for test/* until babel/babel-eslint#33 is resolved

.flowconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[ignore]
2+
.*/lib
3+
.*/test
4+
5+
[include]
6+
7+
[libs]
8+
9+
[options]

.gitignore

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
node_modules
2-
npm-debug.log
31
.DS_Store
2+
*.log
3+
node_modules
44
dist
55
lib
66
coverage
7-
react.js
8-
react-native.js

.npmignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
1-
src
1+
.DS_Store
2+
*.log
23
examples
4+
test
5+
coverage

.travis.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
language: node_js
22
node_js:
3-
- "iojs"
3+
- "iojs-2"
4+
script:
5+
- npm test
6+
- npm run build:examples
7+

examples/async/.babelrc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"stage": 2
3+
}

examples/async/actions/index.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import fetch from 'isomorphic-fetch';
2+
3+
export const REQUEST_POSTS = 'REQUEST_POSTS';
4+
export const RECEIVE_POSTS = 'RECEIVE_POSTS';
5+
export const SELECT_REDDIT = 'SELECT_REDDIT';
6+
export const INVALIDATE_REDDIT = 'INVALIDATE_REDDIT';
7+
8+
export function selectReddit(reddit) {
9+
return {
10+
type: SELECT_REDDIT,
11+
reddit
12+
};
13+
}
14+
15+
export function invalidateReddit(reddit) {
16+
return {
17+
type: INVALIDATE_REDDIT,
18+
reddit
19+
};
20+
}
21+
22+
function requestPosts(reddit) {
23+
return {
24+
type: REQUEST_POSTS,
25+
reddit
26+
};
27+
}
28+
29+
function receivePosts(reddit, json) {
30+
return {
31+
type: RECEIVE_POSTS,
32+
reddit: reddit,
33+
posts: json.data.children,
34+
receivedAt: Date.now()
35+
};
36+
}
37+
38+
function fetchPosts(reddit) {
39+
return dispatch => {
40+
dispatch(requestPosts(reddit));
41+
return fetch(`http://www.reddit.com/r/${reddit}.json`)
42+
.then(req => req.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+
} else if (posts.isFetching) {
52+
return false;
53+
} else {
54+
return posts.didInvalidate;
55+
}
56+
}
57+
58+
export function fetchPostsIfNeeded(reddit) {
59+
return (dispatch, getState) => {
60+
if (shouldFetchPosts(getState(), reddit)) {
61+
return dispatch(fetchPosts(reddit));
62+
}
63+
};
64+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import React, { Component, PropTypes } from 'react';
2+
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+
}
21+
}
22+
23+
Picker.propTypes = {
24+
options: PropTypes.arrayOf(
25+
PropTypes.string.isRequired
26+
).isRequired,
27+
value: PropTypes.string.isRequired,
28+
onChange: PropTypes.func.isRequired
29+
};

examples/async/components/Posts.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import React, { PropTypes, Component } from 'react';
2+
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.data.title}</li>
9+
)}
10+
</ul>
11+
);
12+
}
13+
}
14+
15+
Posts.propTypes = {
16+
posts: PropTypes.array.isRequired
17+
};
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import React, { Component, PropTypes } from 'react';
2+
import { connect } from 'react-redux';
3+
import { selectReddit, fetchPostsIfNeeded, invalidateReddit } from '../actions';
4+
import Picker from '../components/Picker';
5+
import Posts from '../components/Posts';
6+
7+
class AsyncApp extends Component {
8+
constructor(props) {
9+
super(props);
10+
this.handleChange = this.handleChange.bind(this);
11+
this.handleRefreshClick = this.handleRefreshClick.bind(this);
12+
}
13+
14+
componentDidMount() {
15+
const { dispatch, selectedReddit } = this.props;
16+
dispatch(fetchPostsIfNeeded(selectedReddit));
17+
}
18+
19+
componentWillReceiveProps(nextProps) {
20+
if (nextProps.selectedReddit !== this.props.selectedReddit) {
21+
const { dispatch, selectedReddit } = nextProps;
22+
dispatch(fetchPostsIfNeeded(selectedReddit));
23+
}
24+
}
25+
26+
handleChange(nextReddit) {
27+
this.props.dispatch(selectReddit(nextReddit));
28+
}
29+
30+
handleRefreshClick(e) {
31+
e.preventDefault();
32+
33+
const { dispatch, selectedReddit } = this.props;
34+
dispatch(invalidateReddit(selectedReddit));
35+
dispatch(fetchPostsIfNeeded(selectedReddit));
36+
}
37+
38+
render () {
39+
const { selectedReddit, posts, isFetching, lastUpdated } = this.props;
40+
return (
41+
<div>
42+
<Picker value={selectedReddit}
43+
onChange={this.handleChange}
44+
options={['reactjs', 'frontend']} />
45+
<p>
46+
{lastUpdated &&
47+
<span>
48+
Last updated at {new Date(lastUpdated).toLocaleTimeString()}.
49+
{' '}
50+
</span>
51+
}
52+
{!isFetching &&
53+
<a href='#'
54+
onClick={this.handleRefreshClick}>
55+
Refresh
56+
</a>
57+
}
58+
</p>
59+
{isFetching && posts.length === 0 &&
60+
<h2>Loading...</h2>
61+
}
62+
{!isFetching && posts.length === 0 &&
63+
<h2>Empty.</h2>
64+
}
65+
{posts.length > 0 &&
66+
<div style={{ opacity: isFetching ? 0.5 : 1 }}>
67+
<Posts posts={posts} />
68+
</div>
69+
}
70+
</div>
71+
);
72+
}
73+
}
74+
75+
AsyncApp.propTypes = {
76+
selectedReddit: PropTypes.string.isRequired,
77+
posts: PropTypes.array.isRequired,
78+
isFetching: PropTypes.bool.isRequired,
79+
lastUpdated: PropTypes.number,
80+
dispatch: PropTypes.func.isRequired
81+
};
82+
83+
function mapStateToProps(state) {
84+
const { selectedReddit, postsByReddit } = state;
85+
const {
86+
isFetching,
87+
lastUpdated,
88+
items: posts
89+
} = postsByReddit[selectedReddit] || {
90+
isFetching: true,
91+
items: []
92+
};
93+
94+
return {
95+
selectedReddit,
96+
posts,
97+
isFetching,
98+
lastUpdated
99+
};
100+
}
101+
102+
export default connect(mapStateToProps)(AsyncApp);

0 commit comments

Comments
 (0)