rwr-redux 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1630fa9a3b81dc6c3d2ec3c0addd9946d07a86a3
4
- data.tar.gz: a05514f58e13b5c76d097ca240d81b60633b76a9
3
+ metadata.gz: d90aef2f8a8cd36bd034731da93afa59c6645f55
4
+ data.tar.gz: c41a41d679bf180cfd8c6e490c1b27bb393c9ebb
5
5
  SHA512:
6
- metadata.gz: d69c3e0d715fbcb0da13f9e4dab1af464743c2f5cf8ef5b28c923bc3df6c903954668a3c211b51741097f9bfa98f77587a76a8e4c9b9302fa2747c14c374c405
7
- data.tar.gz: 59432c4ff71dc67989c25cd6109053631b43ea3fd686b8dc4ee1557d98707a35305fd826e00232713f1ba20069d0d04743fd468608208802fc455937881b1523
6
+ metadata.gz: 15a686a3d097a50e7fd95f37784ee56be0e280f357c01d0dd2d373140de895a50f20357a7c1a1d00f7b988d57b40d6a76d3edc48edab1bfa831138862373a1e4
7
+ data.tar.gz: 1c6a123ac3b564d88e5fd8c146ea56a54a59d095a409a2094b1679dd01ed9dcb4818c4f10fa6670a5f9079cc5f196c5ad250a0ebdc8eb389eb69f5d4c223081e
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "airbnb",
3
+ "env": {
4
+ "browser": true,
5
+ "node": true,
6
+ "mocha": true
7
+ }
8
+ }
@@ -0,0 +1,4 @@
1
+ Documentation:
2
+ Enabled: false
3
+ Metrics/LineLength:
4
+ Max: 99
@@ -1 +1,16 @@
1
- ## UNRELEASED
1
+ ## 0.2.0
2
+ * add server side rendering
3
+ * add redux-router helpers:
4
+ * js: `registerRouter`
5
+ * Rails: `redux_router`
6
+
7
+ ## 0.1.1 initial release
8
+
9
+ * JS helpers:
10
+ * `registerStore`
11
+ * `registerContainer`
12
+
13
+
14
+ * Rails helpers:
15
+ * `redux_store`
16
+ * `redux_container`
data/README.md CHANGED
@@ -2,24 +2,39 @@ rwr-redux
2
2
  ====
3
3
  [Redux.js](http://redux.js.org/) integration plugin for [react_webpack_rails](https://github.com/netguru/react_webpack_rails).
4
4
 
5
- This integration allows to use redux state containers in a diffrent part of rails views.
5
+ It allows you to use Redux state containers in a different part of Rails views. Thanks to this gem you can use multiple components (Redux containers) on one page. They can easily access the same store and have their state synced.
6
+
7
+ #### Guides and Examples
8
+ * basic react redux rails example: [app](https://github.com/caspg/rails-react-examples/tree/master/basic-redux)
9
+ * how to use Redux and react-router in Rails app: [guide](https://github.com/netguru/rwr-redux/blob/master/docs/rails-redux-router.md) and [example](https://github.com/caspg/rails-react-examples/tree/master/redux-router).
10
+
6
11
 
7
12
  ## Setup
8
13
  * Add `rwr-redux` to your Gemfile:
9
14
 
10
- ```
15
+ ```ruby
11
16
  gem 'rwr-redux'
12
17
  ```
13
18
 
14
- * Install rwr-redux package:
19
+ * Install `rwr-redux` and `redux` packages:
15
20
 
16
21
  ```
17
- $ npm install --save rwr-redux
22
+ $ npm install --save redux react-redux rwr-redux
18
23
  ```
19
24
 
20
25
  ## Usage
21
26
 
22
- ### register store and components in react/index.js
27
+ First of all, you have to register your store and containers in `react/index.js`. Then you can use them in a Rails view using provided helpers.
28
+ When a page is loaded, your container component is wrapped with [`<Provider>`](https://github.com/reactjs/react-redux/blob/master/docs/api.md#provider-store) component and will have access to defined store.
29
+
30
+
31
+ ### register integrations, store and components in `react/index.js`
32
+
33
+ Register integrations:
34
+ ```js
35
+ integrationsManager.register('redux-store', RWRRedux.storeIntegrationWrapper);
36
+ integrationsManager.register('redux-container', RWRRedux.containerIntegrationWrapper);
37
+ ```
23
38
 
24
39
  Register store:
25
40
 
@@ -35,7 +50,17 @@ import Container from './containers/MyContainerName';
35
50
  RWRRedux.registerContainer('MyContainerName', Container);
36
51
  ```
37
52
 
38
- ### use registered store and componetns in Rails view
53
+ ### store
54
+
55
+ Registered store has to be a function which accepts **initial state** as an argument and returns store object:
56
+
57
+ ```js
58
+ export default function configureStore(initialState) {
59
+ return createStore(rootReducer, initialState);
60
+ }
61
+ ```
62
+
63
+ ### use registered store and components in Rails view
39
64
 
40
65
  Define store with initial state:
41
66
 
@@ -55,23 +80,65 @@ If you have more than one store in a view, you can specify `store_name`:
55
80
  <%= redux_container 'MyContainerName', store_name: 'MyStoreName' %>
56
81
  ```
57
82
 
58
- ### using redux [DevTools](https://github.com/gaearon/redux-devtools)
83
+ ## Usage with react-redux-router
59
84
 
60
- **Use DevTools only in a development, below code has to be excluded in production.**
85
+ If you want to use router in your redux app, you have to only create routes component. `rwr-redux` will wrap it with `<Router>` and `<Provider>`components, and also, will sync history with the store. Only `browserHistory` is supported.
61
86
 
62
- register in `react/index.js`:
87
+ ### example routes
88
+ `app/react/routes/index.js`
63
89
 
64
90
  ```js
65
- import DevTools from './containers/DevTools';
66
- RWRRedux.registerContainer('DevTools', DevTools);
91
+ export default (
92
+ <Route path="/" component={App}>
93
+ <Route path="about" component={About} />
94
+ </Route>
95
+ )
67
96
  ```
68
97
 
69
- use in Rails view:
98
+ ### register integration and routes in `react/index.js`
99
+
100
+ ```js
101
+ integrationsManager.register('redux-router', RWRRedux.routerIntegrationWrapper);
102
+ ```
103
+
104
+ ```js
105
+ import RoutesName from './routes';
106
+ RWRRedux.registerRoutes('RoutesName', RoutesName);
107
+ ```
108
+
109
+ ### use registered routes in Rails view
110
+
111
+ Do not forget to use `redux_store` helper.
70
112
 
71
113
  ```erb
72
- <%= redux_container 'DevTools' %>
114
+ <%= redux_store 'MyStoreName', { foo: @bar } %>
115
+
116
+ <%= redux_router 'RoutesName' %>
73
117
  ```
74
118
 
119
+ ## Server Side Rendering
120
+
121
+ More info how to use server side rendering with `react_webpack_rails`: [click](https://github.com/netguru/react_webpack_rails/blob/master/docs/server_side_rendering.md)
122
+
123
+ Rails routes has to be properly setup:
124
+
125
+ ```rb
126
+ get '/server_side/' => 'pages#server_side'
127
+ get '/server_side/*path' => 'pages#server_side'
128
+ ```
129
+
130
+ To enable server side rendering pass `server_side: true` to helpers options:
131
+
132
+ ```erb
133
+ <%= redux_store 'MyStoreName', { foo: @bar }, server_side: true %>
134
+
135
+ <%= redux_container 'MyContainerName', server_side: true %>
136
+
137
+ <%= redux_router 'RoutesName', server_side: true %>
138
+ ```
139
+
140
+ **NOTE**: `rwr-redux` automatically handles matching, redirecting and routing errors. Redirects and 404's are passed to Rails and handled there so you will be redirected or get 404 page like in normal Rails app.
141
+
75
142
  ## Contributing
76
143
  ## Issues
77
144
 
data/Rakefile CHANGED
@@ -3,7 +3,7 @@ require 'rspec/core/rake_task'
3
3
 
4
4
  namespace :test do
5
5
  desc 'Run all tests'
6
- task all: [:node, :gem] do
6
+ task all: [:node, :gem, :rails4] do
7
7
  puts 'Finished all tests, yay!'
8
8
  end
9
9
 
@@ -16,13 +16,27 @@ namespace :test do
16
16
  task :gem do
17
17
  sh %Q(bundle exec rspec spec/rwr-redux.rb)
18
18
  end
19
+
20
+ desc 'Run rspec for rails4 application'
21
+ task :rails4 do
22
+ Bundler.with_clean_env do
23
+ sh %Q(
24
+ cd spec/rails4_dummy_app &&
25
+ npm run build &&
26
+ npm run rwr-background-node &&
27
+ sleep 4 &&
28
+ bundle exec rspec &&
29
+ npm run rwr-stop-background-node
30
+ )
31
+ end
32
+ end
19
33
  end
20
34
 
21
35
  task default: 'test:all'
22
36
 
23
37
  namespace :setup do
24
38
  desc 'Prepare every environment'
25
- task all: [:node, :gem] do
39
+ task all: [:node, :gem, :rails4] do
26
40
  puts 'Prepared all, yay!'
27
41
  end
28
42
 
@@ -35,4 +49,9 @@ namespace :setup do
35
49
  task :gem do
36
50
  sh %Q(bundle install)
37
51
  end
52
+
53
+ desc 'Prepare rails4 test app dependencies'
54
+ task :rails4 do
55
+ sh %Q(npm install && cd spec/rails4_dummy_app && npm install && bundle install)
56
+ end
38
57
  end
@@ -0,0 +1,108 @@
1
+ # react-router-redux in Rails app
2
+
3
+ Adding multiple Redux components within Rails view is really easy thanks to [react_webpack_rails](https://github.com/netguru/react_webpack_rails) and [rwr-redux](https://github.com/netguru/rwr-redux).
4
+
5
+ This guide shows how to do routing with `react-router` and how to sync state between components with Redux store using `react-router-redux`.
6
+ Let's say you would like to have two components which shares the same store, navbar and main app component.
7
+
8
+ If you want check the source code right away, you can find example app [here](https://github.com/caspg/rails-react-examples/tree/master/redux-router).
9
+
10
+ ## Setup
11
+
12
+ * [react_webpack_rails](https://github.com/netguru/react_webpack_rails) and [rwr-redux](https://github.com/netguru/rwr-redux) have to be added and to your app
13
+ * install react-router and react-router-redux:
14
+ ```bash
15
+ $ npm install --save react-router react-router-redux
16
+ ```
17
+
18
+ ## Main app component
19
+
20
+ In your root component add `<Router>` component and sync history with store.
21
+
22
+ `react/containers/Root.jsx` [example](https://github.com/caspg/rails-react-examples/blob/master/redux-router/app/react/containers/Root.jsx)
23
+ ```jsx
24
+ import React, { Component } from 'react';
25
+ import { Router, Route, IndexRoute, browserHistory } from 'react-router';
26
+ import { syncHistoryWithStore } from 'react-router-redux';
27
+ import RWRRedux from 'rwr-redux';
28
+
29
+ import App from './App';
30
+ (...)
31
+
32
+ export default class Root extends Component {
33
+ componentWillMount() {
34
+ const mountedStore = RWRRedux.getStore();
35
+ this.history = syncHistoryWithStore(browserHistory, mountedStore);
36
+ }
37
+
38
+ render() {
39
+ return (
40
+ <Router history={this.history} >
41
+ <Route path="/" component={App}>
42
+ (...)
43
+ </Route>
44
+ </Router>
45
+ );
46
+ }
47
+ }
48
+ ```
49
+
50
+ In `componentWillMount()` method, browserHistory is synced with [registered store](https://github.com/netguru/rwr-redux#register-store-and-components-in-reactindexjs). Store can be accessed by `getStore()` function provided by `rwr-redux` package.
51
+
52
+ Within this component you can navigate with `<Link>` components ([example](https://github.com/caspg/rails-react-examples/blob/master/redux-router/app/react/components/TabItem.jsx#L11)).
53
+
54
+ ## Store
55
+
56
+ Navbar component will issue [navigation events](https://github.com/reactjs/react-router-redux#what-if-i-want-to-issue-navigation-events-via-redux-actions) via Redux actions. Those events will change state and cause main component to rerender.
57
+
58
+ To make it works, you need to apply middleware to the store:
59
+ `react/store/index.js`
60
+ ```jsx
61
+ import { createStore, applyMiddleware } from 'redux';
62
+ import { routerMiddleware } from 'react-router-redux'
63
+ import { browserHistory } from 'react-router';
64
+
65
+ import rootReducer from '../reducers';
66
+
67
+ export default function configureStore(initialState) {
68
+ const middleware = routerMiddleware(browserHistory)
69
+
70
+ return createStore(
71
+ rootReducer,
72
+ initialState,
73
+ applyMiddleware(middleware)
74
+ );
75
+ }
76
+ ```
77
+
78
+ ## Navbar component
79
+
80
+ `react/containers/Navbar.jsx` [example](https://github.com/caspg/rails-react-examples/blob/master/redux-router/app/react/containers/Navbar.jsx#L15)
81
+
82
+ Import `push` method from react-router-redux:
83
+ ```jsx
84
+ import { push } from 'react-router-redux';
85
+ ```
86
+
87
+ And now you can dispatch an action with navigation event:
88
+ ```jsx
89
+ this.props.dispatch(push(path));
90
+ ```
91
+
92
+ ## Rails part
93
+
94
+ Add wildcard route:
95
+
96
+ `routes.rb`
97
+ ```ruby
98
+ root 'home#index'
99
+ get '/*path' => 'home#index'
100
+ ```
101
+
102
+ Now you can use rails helpers in appropriate view:
103
+ ```erb
104
+ <%= redux_store 'StoreName', { initial_state: @initial_state_from_controller } %>
105
+ <%= redux_container 'Navbar' %>
106
+
107
+ <%= redux_container 'MainApp' %>
108
+ ```
@@ -1,109 +1,22 @@
1
1
  import version from './version';
2
-
3
- import React from 'react';
4
- import { render, unmountComponentAtNode } from 'react-dom';
5
- import { renderToString } from 'react-dom/server';
6
- import { Provider } from 'react-redux'
7
-
8
- import { isFunction, isReduxStore } from './utils/validators';
2
+ import ReduxStore from './integrations/redux-store';
3
+ import ReduxContainer from './integrations/redux-container';
4
+ import ReduxRouter from './integrations/redux-router';
9
5
 
10
6
  class RWRRedux {
11
7
  constructor() {
12
8
  this.version = version;
13
- this.registeredStores = {};
14
- this.mountedStores = {};
15
- this.defaultStore = null;
16
- this.containers = {};
17
-
18
- this.registerStore = this.registerStore.bind(this);
19
- this.mountStore = this.mountStore.bind(this);
20
- this.getStore = this.getStore.bind(this);
21
- this.registerContainer = this.registerContainer.bind(this);
22
- this.getContainer = this.getContainer.bind(this);
23
- this.createContainer = this.createContainer.bind(this);
24
- this.createRootComponent = this.createRootComponent.bind(this);
25
- this.renderContainer = this.renderContainer.bind(this);
26
- this.unmountContainer = this.unmountContainer.bind(this);
27
- this.renderContainerToString = this.renderContainerToString.bind(this);
28
- }
29
-
30
- registerStore(name, store) {
31
- isFunction(store, `Error when registering '${name}' store: must be a function.`);
32
- this.registeredStores[name] = store;
33
- }
34
-
35
- mountStore(name, props) {
36
- const store = this.registeredStores[name];
37
- isFunction(store, `Error when mounting '${name}' store: must be a function.`);
38
-
39
- const storeObject = store(props);
40
- isReduxStore(storeObject, `Error when mounting '${name}' store: must be a valid Redux store.`);
41
- this.mountedStores[name] = storeObject;
42
- this.defaultStore = storeObject;
43
- }
44
-
45
- getStore(name) {
46
- if (name) {
47
- return this.mountedStores[name];
48
- } else {
49
- return this.defaultStore;
50
- }
51
- }
52
-
53
- registerContainer(name, container) {
54
- this.containers[name] = container;
55
- }
56
-
57
- getContainer(name) {
58
- return this.containers[name];
59
- }
60
-
61
- createContainer(name) {
62
- const constructor = this.getContainer(name);
63
- return React.createElement(constructor);
64
- }
65
-
66
- createRootComponent(name, storeName) {
67
- const container = this.createContainer(name);
68
- return React.createElement(Provider, { store: this.getStore(storeName) }, container);
69
- }
70
-
71
- renderContainer(name, node, storeName) {
72
- const rootComponent = this.createRootComponent(name, storeName);
73
- render(rootComponent, node);
74
- }
75
-
76
- unmountContainer(node) {
77
- unmountComponentAtNode(node);
78
- }
79
-
80
- renderContainerToString(name, storeName) {
81
- const rootComponent = this.createRootComponent(name, storeName);
82
- renderToString(rootComponent);
83
- }
84
-
85
- get storeIntegrationWrapper() {
86
- return {
87
- mount: function _mount(_, payload) {
88
- this.mountStore(payload.name, payload.props);
89
- }.bind(this)
90
- }
91
- }
92
9
 
93
- get containerIntegrationWrapper() {
94
- return {
95
- mount: function _mount(node, payload) {
96
- this.renderContainer(payload.name, node, payload.storeName);
97
- }.bind(this),
10
+ this.registerStore = ReduxStore.registerStore;
11
+ this.mountStore = ReduxStore.mountStore;
12
+ this.getStore = ReduxStore.getStore;
13
+ this.storeIntegrationWrapper = ReduxStore.integrationWrapper;
98
14
 
99
- unmount: function _unmount(node) {
100
- this.unmountContainer(node);
101
- }.bind(this),
15
+ this.registerContainer = ReduxContainer.registerContainer;
16
+ this.containerIntegrationWrapper = ReduxContainer.integrationWrapper;
102
17
 
103
- nodeRun: function _prerender(payload) {
104
- return this.renderContainerToString(payload.name);
105
- }.bind(this)
106
- }
18
+ this.registerRoutes = ReduxRouter.registerRoutes;
19
+ this.routerIntegrationWrapper = ReduxRouter.integrationWrapper;
107
20
  }
108
21
  }
109
22