Skip to content

Commit b93f39c

Browse files
committed
Merge pull request #14 from ganarajpr/master
LocalProvider to solve the issue of Global vs Local changes
2 parents 00250e6 + 716bd6e commit b93f39c

32 files changed

+739
-0
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"presets": ["es2015", "stage-0", "react"]
3+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
node_modules/
2+
build/
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Scalable Frontend With Redux and Sagas
2+
3+
This project is an attempt to address the problem raised at
4+
[slorber/scalable-frontend-with-elm-or-redux](https://github.com/slorber/scalable-frontend-with-elm-or-redux)
5+
by [@sebastienlorber](https://twitter.com/sebastienlorber).
6+
7+
**Note:** The overall application and some code ( Components ) were copied over from
8+
Jaysoo's implementation - but the architecture is completely different between
9+
the two implementations.
10+
11+
## Notable Differences
12+
13+
One of the things I had to invent to make this architecture happen is the **LocalProvider**.
14+
This is a Provider higher order component that provides the store to all its children
15+
through the context. In this respect its quite similiar to the *Original* Redux Provider.
16+
The important difference is that it allows you to have *local* state maintained in a
17+
Redux store. There are multiple stores ( kind of a store hierarchy! ) but all dispatched
18+
actions are *listenable* at the global store. This allows local isolated modifications
19+
while also allowing *global* signalling mechanism. It works exactly
20+
the same as using *setState* but with the added benefit of being able to move any component
21+
from a local state to a global state with very few changes.
22+
23+
## Downsides
24+
25+
- The complete application state is not *currently* serializable ( atleast completely! ).
26+
- Its not possible to react to *local* changes in other *local* locations.
27+
28+
## Running App
29+
30+
```
31+
npm install
32+
npm start
33+
```
34+
35+
Browse to [http://localhost:8080](http://localhost:8080), and see the
36+
"Real World" Example at the very bottom of the page.
37+
38+
- The GIFs section allows you to add a GIF for the entered topic.
39+
- The toggle button can be *on* or *off*.
40+
- The counter can be *incremented* or *decremented*.
41+
- Whenever a new GIF is fetched (either by adding or requesting more),
42+
the counter is incremented by *1* if button is off or `counter < 10`,
43+
otherwise it is incremented by *2*.
44+
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"name": "scalable-frontend-with-redux-saga-localstate-ganaraj",
3+
"version": "1.0.0",
4+
"description": "",
5+
"main": "index.js",
6+
"scripts": {
7+
"build": "node_modules/.bin/webpack",
8+
"start": "node_modules/.bin/webpack-dev-server",
9+
"test": "node_modules/.bin/mocha --require babel-core/register --recursive src/**/__tests__/**/*-test.js"
10+
},
11+
"author": "Ganaraj P R <[email protected]> (http://www.dhi.io/)",
12+
"license": "ISC",
13+
"devDependencies": {
14+
"babel-core": "^6.6.4",
15+
"babel-loader": "^6.2.4",
16+
"babel-preset-es2015": "^6.6.0",
17+
"babel-preset-react": "^6.5.0",
18+
"babel-preset-stage-0": "^6.5.0",
19+
"css-loader": "^0.23.1",
20+
"expect": "^1.14.0",
21+
"mocha": "^2.4.5",
22+
"react-hot-loader": "^1.3.0",
23+
"redux-logger": "^2.6.1",
24+
"style-loader": "^0.13.0",
25+
"superagent": "^1.8.0",
26+
"webpack": "^1.12.14",
27+
"webpack-dev-server": "^1.14.1"
28+
},
29+
"dependencies": {
30+
"babel-polyfill": "^6.6.1",
31+
"react": "^0.14.7",
32+
"react-dom": "^0.14.7",
33+
"react-redux": "^4.4.0",
34+
"redux": "^3.3.1",
35+
"redux-saga": "^0.9.3"
36+
}
37+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import React, {createElement, Component} from 'react';
2+
import Provider from 'react-redux';
3+
import { createStore, applyMiddleware } from 'redux';
4+
5+
const localState = (component, localReducer, mws=[]) => {
6+
7+
class LocalProvider extends Component {
8+
constructor(props, context) {
9+
super(props, context);
10+
this.parentStore = context.store;
11+
this.listener = this.listener.bind(this);
12+
this.localStore = createStore(localReducer,
13+
applyMiddleware.apply(null, [this.listener, ...mws]));
14+
this.overrideGetState();
15+
}
16+
17+
overrideGetState(){
18+
const localGetState = this.localStore.getState;
19+
this.localStore.getState = () => ({
20+
...this.parentStore.getState(),
21+
local: localGetState()
22+
});
23+
}
24+
25+
getChildContext() {
26+
return { store: this.localStore };
27+
}
28+
29+
listener() {
30+
return (next) => (action) => {
31+
let returnValue = next(action);
32+
this.parentStore.dispatch(action);
33+
return returnValue;
34+
};
35+
};
36+
37+
render() {
38+
return createElement(component, this.props);
39+
}
40+
}
41+
LocalProvider.contextTypes = {store: React.PropTypes.object};
42+
LocalProvider.childContextTypes = {store: React.PropTypes.object};
43+
return LocalProvider;
44+
};
45+
46+
export default localState;
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import React from 'react'
2+
import { bindActionCreators } from 'redux'
3+
import { connect } from 'react-redux'
4+
import * as actions from './actions';
5+
6+
export const Counter = ({ count, increment, decrement }) => (
7+
<div>
8+
<button style={{ width: '50px' }} onClick={() => increment()}>
9+
+
10+
</button>
11+
<span style={{ paddingLeft: '50px', paddingRight: '50px' }}>
12+
{count}
13+
</span>
14+
<button style={{ width: '50px' }} onClick={() => decrement()}>
15+
-
16+
</button>
17+
</div>
18+
)
19+
20+
function mapStateToProps(state, ownProps) {
21+
return {
22+
count: state.counter
23+
}
24+
}
25+
26+
function mapDispatchToProps(dispatch, ownProps) {
27+
return {
28+
increment: () => dispatch(actions.increment()),
29+
decrement: () => dispatch(actions.decrement())
30+
};
31+
}
32+
33+
export default connect(
34+
mapStateToProps,
35+
mapDispatchToProps
36+
)(Counter);
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
export const INCREMENT = 'INCREMENT';
2+
export const DECREMENT = 'DECREMENT';
3+
4+
export const increment = () => {
5+
return {
6+
type: INCREMENT
7+
}
8+
}
9+
10+
export const decrement = () => {
11+
return {
12+
type: DECREMENT
13+
}
14+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import * as actions from './actions';
2+
import reducer from './reducer';
3+
import Container from './Container';
4+
5+
export { actions, reducer, Container };
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { INCREMENT, DECREMENT } from './actions';
2+
3+
const initialState = 0;
4+
5+
export default (state = initialState, action) => {
6+
switch (action.type) {
7+
case INCREMENT:
8+
return state+1;
9+
case DECREMENT:
10+
return state-1;
11+
default:
12+
return state;
13+
}
14+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import './styles.css'
2+
import 'babel-polyfill'
3+
import React from 'react'
4+
import { render } from 'react-dom'
5+
import { Provider } from 'react-redux'
6+
import { App, reducer } from './main'
7+
import { createStore, applyMiddleware } from 'redux'
8+
import createSagaMiddleware from 'redux-saga';
9+
import createLogger from 'redux-logger';
10+
import saga from './saga';
11+
12+
const logger = createLogger();
13+
const sagaMiddleware = createSagaMiddleware(saga)
14+
15+
const store = createStore(reducer,
16+
applyMiddleware(sagaMiddleware, logger)
17+
);
18+
19+
render(
20+
<Provider store={store}>
21+
<App/>
22+
</Provider>
23+
,
24+
document.getElementById('app')
25+
)

0 commit comments

Comments
 (0)