Skip to content

Commit df77edb

Browse files
author
nostophilia
committed
Revise "Hello World" Redux example
1 parent 5e5b92e commit df77edb

File tree

11 files changed

+67
-152
lines changed

11 files changed

+67
-152
lines changed

lib/generators/react_on_rails/react_with_redux_generator.rb

-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ def copy_base_redux_files
1717
client/app/bundles/HelloWorld/containers/HelloWorld.jsx
1818
client/app/bundles/HelloWorld/constants/helloWorldConstants.jsx
1919
client/app/bundles/HelloWorld/reducers/helloWorldReducer.jsx
20-
client/app/bundles/HelloWorld/reducers/index.jsx
2120
client/app/bundles/HelloWorld/store/helloWorldStore.jsx).each do |file|
2221
copy_file(base_path + file, file)
2322
end

lib/generators/react_on_rails/templates/base/base/client/app/bundles/HelloWorld/components/HelloWorldWidget.jsx.tt

+28-34
Original file line numberDiff line numberDiff line change
@@ -4,39 +4,33 @@
44
import React, { PropTypes } from 'react';
55

66
// Simple example of a React "dumb" component
7-
export default class HelloWorldWidget extends React.Component {
8-
static propTypes = {
9-
// If you have lots of data or action properties, you should consider grouping them by
10-
// passing two properties: "data" and "actions".
11-
updateName: PropTypes.func.isRequired,
12-
name: PropTypes.string.isRequired,
13-
};
7+
const HelloWorldWidget = (props) => {
8+
const { name, updateName } = props;
149

15-
// React will automatically provide us with the event `e`
16-
handleChange(e) {
17-
const name = e.target.value;
18-
this.props.updateName(name);
19-
}
10+
return (
11+
<div className="container">
12+
<h3>
13+
Hello, {name}!
14+
</h3>
15+
<hr />
16+
<form className="form-horizontal">
17+
<label htmlFor="name">
18+
Say hello to:
19+
</label>
20+
<input
21+
type="text" value={name} id="name"
22+
onChange={(e) => updateName(e.target.value)}
23+
/>
24+
</form>
25+
</div>
26+
);
27+
};
2028

21-
render() {
22-
const { name } = this.props;
23-
return (
24-
<div className="container">
25-
<h3>
26-
Hello, {name}!
27-
</h3>
28-
<hr />
29-
<form className="form-horizontal">
30-
<label>
31-
Say hello to:
32-
</label>
33-
<input
34-
type="text"
35-
value={name}
36-
onChange={e => this.handleChange(e)}
37-
/>
38-
</form>
39-
</div>
40-
);
41-
}
42-
}
29+
HelloWorldWidget.propTypes = {
30+
// If you have lots of data or action properties, you should consider grouping them by
31+
// passing two properties: "data" and "actions".
32+
updateName: PropTypes.func.isRequired,
33+
name: PropTypes.string.isRequired,
34+
};
35+
36+
export default HelloWorldWidget;

lib/generators/react_on_rails/templates/base/base/client/package.json.tt

-8
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,13 @@
2424
"babel-preset-stage-0": "^6.5.0",
2525
"es5-shim": "^4.5.7",
2626
"expose-loader": "^0.7.1",
27-
<%- if options.redux? -%>
28-
"immutable": "^3.7.6",
29-
<%- end -%>
3027
"imports-loader": "^0.6.5",
31-
<%- if options.redux? -%>
32-
"mirror-creator": "1.1.0",
33-
<%- end -%>
3428
"react": "^0.14.8 || ^15.0.0",
3529
"react-dom": "^0.14.8 || ^15.0.0",
3630
"react-on-rails": "<%= VersionSyntaxConverter.new.rubygem_to_npm %>",
3731
<%- if options.redux? -%>
3832
"react-redux": "^4.4.1",
3933
"redux": "^3.3.1",
40-
"redux-promise": "^0.5.3",
41-
"redux-thunk": "^2.0.1",
4234
<%- end -%>
4335
"webpack": "^1.12.14"
4436
},
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1+
/* eslint-disable import/prefer-default-export */
2+
13
import actionTypes from '../constants/helloWorldConstants';
24

3-
export function updateName(name) {
4-
return {
5-
type: actionTypes.HELLO_WORLD_NAME_UPDATE,
6-
name,
7-
};
8-
}
5+
export const updateName = (text) => ({
6+
type: actionTypes.HELLO_WORLD_NAME_UPDATE,
7+
text,
8+
});
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,3 @@
1-
// See https://www.npmjs.com/package/mirror-creator
2-
// Allows us to set up constants in a slightly more concise syntax. See:
3-
// client/app/bundles/HelloWorld/actions/helloWorldActionCreators.jsx
4-
import mirrorCreator from 'mirror-creator';
5-
6-
const actionTypes = mirrorCreator([
7-
'HELLO_WORLD_NAME_UPDATE',
8-
]);
9-
10-
// actionTypes = {HELLO_WORLD_NAME_UPDATE: "HELLO_WORLD_NAME_UPDATE"}
11-
// Notice how we don't have to duplicate HELLO_WORLD_NAME_UPDATE twice
12-
// thanks to mirror-creator.
13-
export default actionTypes;
1+
export default {
2+
HELLO_WORLD_NAME_UPDATE: 'HELLO_WORLD_NAME_UPDATE',
3+
};
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,27 @@
11
import React, { PropTypes } from 'react';
2-
import HelloWorldWidget from '../components/HelloWorldWidget';
32
import { connect } from 'react-redux';
4-
import { bindActionCreators } from 'redux';
5-
import Immutable from 'immutable';
6-
import * as helloWorldActionCreators from '../actions/helloWorldActionCreators';
3+
import HelloWorldWidget from '../components/HelloWorldWidget';
4+
import * as actions from '../actions/helloWorldActionCreators';
75

8-
function select(state) {
9-
// Which part of the Redux global state does our component want to receive as props?
10-
// Note the use of `$$` to prefix the property name because the value is of type Immutable.js
11-
return { $$helloWorldStore: state.$$helloWorldStore };
12-
}
6+
// Which part of the Redux global state does our component want to receive as props?
7+
const mapStateToProps = (state) => ({ name: state.name });
138

149
// Simple example of a React "smart" component
1510
const HelloWorld = (props) => {
16-
const { dispatch, $$helloWorldStore } = props;
17-
const actions = bindActionCreators(helloWorldActionCreators, dispatch);
18-
const { updateName } = actions;
19-
const name = $$helloWorldStore.get('name');
11+
const { name, updateName } = props;
2012

2113
// This uses the ES2015 spread operator to pass properties as it is more DRY
2214
// This is equivalent to:
23-
// <HelloWorldWidget $$helloWorldStore={$$helloWorldStore} actions={actions} />
24-
return (
25-
<HelloWorldWidget {...{ updateName, name }} />
26-
);
15+
// <HelloWorldWidget name={name} updateName={updateName} />
16+
return <HelloWorldWidget {...{ name, updateName }} />;
2717
};
2818

2919
HelloWorld.propTypes = {
30-
dispatch: PropTypes.func.isRequired,
31-
32-
// This corresponds to the value used in function select above.
33-
// We prefix all property and variable names pointing to Immutable.js objects with '$$'.
34-
// This allows us to immediately know we don't call $$helloWorldStore['someProperty'], but
35-
// instead use the Immutable.js `get` API for Immutable.Map
36-
$$helloWorldStore: PropTypes.instanceOf(Immutable.Map).isRequired,
20+
name: PropTypes.string.isRequired,
21+
updateName: PropTypes.func.isRequired,
3722
};
3823

3924
// Don't forget to actually use connect!
4025
// Note that we don't export HelloWorld, but the redux "connected" version of it.
4126
// See https://github.com/reactjs/react-redux/blob/master/docs/api.md#examples
42-
export default connect(select)(HelloWorld);
27+
export default connect(mapStateToProps, actions)(HelloWorld);
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,16 @@
1-
import Immutable from 'immutable';
2-
31
import actionTypes from '../constants/helloWorldConstants';
42

5-
export const $$initialState = Immutable.fromJS({
6-
name: '', // this is the default state that would be used if one were not passed into the store
7-
});
8-
9-
export default function helloWorldReducer($$state = $$initialState, action) {
10-
const { type, name } = action;
3+
const helloWorldReducer = (state = { name: '' }, action) => {
4+
const { type, text } = action;
115

126
switch (type) {
137
case actionTypes.HELLO_WORLD_NAME_UPDATE:
14-
return $$state.set('name', name);
158

9+
// use spread operator to avoid mutating this state
10+
return { ...state, name: text };
1611
default:
17-
return $$state;
12+
return state;
1813
}
19-
}
14+
};
15+
16+
export default helloWorldReducer;

lib/generators/react_on_rails/templates/redux/base/client/app/bundles/HelloWorld/reducers/index.jsx

-13
This file was deleted.

lib/generators/react_on_rails/templates/redux/base/client/app/bundles/HelloWorld/startup/HelloWorldApp.jsx.tt

+6-10
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,19 @@ import React from 'react';
22
import ReactOnRails from 'react-on-rails';
33
import { Provider } from 'react-redux';
44

5-
import createStore from '../store/helloWorldStore';
5+
import configureStore from '../store/helloWorldStore';
66
import HelloWorld from '../containers/HelloWorld';
77

88
// See documentation for https://github.com/reactjs/react-redux.
99
// This is how you get props from the Rails view into the redux store.
1010
// This code here binds your smart component to the redux store.
1111
// railsContext provides contextual information especially useful for server rendering, such as
1212
// knowing the locale. See the React on Rails documentation for more info on the railsContext
13-
const HelloWorldApp = (props, _railsContext) => {
14-
const store = createStore(props);
15-
const reactComponent = (
16-
<Provider store={store}>
17-
<HelloWorld />
18-
</Provider>
19-
);
20-
return reactComponent;
21-
};
13+
const HelloWorldApp = (props, _railsContext) => (
14+
<Provider store={configureStore(props)}>
15+
<HelloWorld />
16+
</Provider>
17+
);
2218

2319
// This is how react_on_rails can see the HelloWorldApp in the browser.
2420
ReactOnRails.register({ HelloWorldApp });
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,8 @@
1-
import { compose, createStore, applyMiddleware, combineReducers } from 'redux';
1+
import { createStore } from 'redux';
2+
import helloWorldReducer from '../reducers/helloWorldReducer';
23

3-
// See
4-
// https://github.com/gaearon/redux-thunk and http://redux.js.org/docs/advanced/AsyncActions.html
5-
// This is not actually used for this simple example, but you'd probably want to use this
6-
// once your app has asynchronous actions.
7-
import thunkMiddleware from 'redux-thunk';
4+
const configureStore = (railsProps) => (
5+
createStore(helloWorldReducer, railsProps)
6+
);
87

9-
import reducers from '../reducers';
10-
import { initialStates } from '../reducers';
11-
12-
export default props => {
13-
// This is how we get initial props Rails into redux.
14-
const { name } = props;
15-
const { $$helloWorldState } = initialStates;
16-
17-
// Redux expects to initialize the store using an Object, not an Immutable.Map
18-
const initialState = {
19-
$$helloWorldStore: $$helloWorldState.merge({
20-
name,
21-
}),
22-
};
23-
24-
const reducer = combineReducers(reducers);
25-
const composedStore = compose(
26-
applyMiddleware(thunkMiddleware)
27-
);
28-
const storeCreator = composedStore(createStore);
29-
const store = storeCreator(reducer, initialState);
30-
31-
return store;
32-
};
8+
export default configureStore;

spec/react_on_rails/support/shared_examples/react_with_redux_generator_examples.rb

-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
client/app/bundles/HelloWorld/containers/HelloWorld.jsx
99
client/app/bundles/HelloWorld/constants/helloWorldConstants.jsx
1010
client/app/bundles/HelloWorld/reducers/helloWorldReducer.jsx
11-
client/app/bundles/HelloWorld/reducers/index.jsx
1211
client/app/bundles/HelloWorld/store/helloWorldStore.jsx
1312
client/app/bundles/HelloWorld/startup/HelloWorldApp.jsx).each { |file| assert_file(file) }
1413
end

0 commit comments

Comments
 (0)