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

+6
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

+9
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

+2-4
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

+4-1
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

+5-1
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

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"stage": 2
3+
}

examples/async/actions/index.js

+64
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+
}

examples/async/components/Picker.js

+29
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

+17
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+
};

examples/async/containers/AsyncApp.js

+102
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);

examples/async/containers/Root.js

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import React, { Component } from 'react';
2+
import { Provider } from 'react-redux';
3+
import configureStore from '../store/configureStore';
4+
import AsyncApp from './AsyncApp';
5+
6+
const store = configureStore();
7+
8+
export default class Root extends Component {
9+
render() {
10+
return (
11+
<Provider store={store}>
12+
{() => <AsyncApp />}
13+
</Provider>
14+
);
15+
}
16+
}

examples/async/index.html

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<html>
2+
<head>
3+
<title>Redux async example</title>
4+
</head>
5+
<body>
6+
<div id="root">
7+
</div>
8+
</body>
9+
<script src="/static/bundle.js"></script>
10+
</html>

examples/async/index.js

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import 'babel-core/polyfill';
2+
3+
import React from 'react';
4+
import Root from './containers/Root';
5+
6+
React.render(
7+
<Root />,
8+
document.getElementById('root')
9+
);

examples/async/package.json

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
{
2+
"name": "redux-async-example",
3+
"version": "0.0.0",
4+
"description": "Redux async example",
5+
"main": "server.js",
6+
"scripts": {
7+
"start": "node server.js"
8+
},
9+
"repository": {
10+
"type": "git",
11+
"url": "https://github.com/gaearon/redux.git"
12+
},
13+
"keywords": [
14+
"react",
15+
"reactjs",
16+
"hot",
17+
"reload",
18+
"hmr",
19+
"live",
20+
"edit",
21+
"webpack",
22+
"flux"
23+
],
24+
"license": "MIT",
25+
"bugs": {
26+
"url": "https://github.com/gaearon/redux/issues"
27+
},
28+
"homepage": "https://github.com/gaearon/redux#readme",
29+
"dependencies": {
30+
"isomorphic-fetch": "^2.1.1",
31+
"react": "^0.13.3",
32+
"react-redux": "^0.8.0",
33+
"redux": "^1.0.0-rc",
34+
"redux-logger": "0.0.3",
35+
"redux-thunk": "^0.1.0"
36+
},
37+
"devDependencies": {
38+
"babel-core": "^5.6.18",
39+
"babel-loader": "^5.1.4",
40+
"expect": "^1.6.0",
41+
"jsdom": "^5.6.1",
42+
"mocha": "^2.2.5",
43+
"mocha-jsdom": "^1.0.0",
44+
"node-libs-browser": "^0.5.2",
45+
"react-hot-loader": "^1.2.8",
46+
"webpack": "^1.9.11",
47+
"webpack-dev-server": "^1.9.0"
48+
}
49+
}

0 commit comments

Comments
 (0)