Skip to content

Commit

Permalink
Merge pull request #65 from ekosz/patch-1
Browse files Browse the repository at this point in the history
Add redux examples
  • Loading branch information
taion authored Feb 22, 2017
2 parents 9779b06 + 875672f commit f094b36
Show file tree
Hide file tree
Showing 13 changed files with 479 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ export default AppPage;
- [Global pending state](/examples/global-pending)
- [Transition hook usage](/examples/transition-hook)
- [Server-side rendering](/examples/universal)
- [Shared redux store](/examples/redux)
- [Server-side rendering with shared redux store](/examples/universal-redux)

## Extensions

Expand Down
12 changes: 12 additions & 0 deletions examples/redux/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Found Redux Example

This example uses the same route configuration as the [basic JSX example](../basic-jsx), but uses shared redux store between found and the app.

## Usage

```
$ npm i
$ npm start
```

Then open [http://localhost:3000/](http://localhost:3000/) in your browser.
19 changes: 19 additions & 0 deletions examples/redux/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "redux",
"version": "0.1.0",
"private": true,
"devDependencies": {
"react-scripts": "0.9.0"
},
"dependencies": {
"farce": "^0.2.1",
"found": "../..",
"react": "^15.4.2",
"react-dom": "^15.4.2",
"react-redux": "^5.0.2",
"redux": "^3.6.0"
},
"scripts": {
"start": "react-scripts start"
}
}
14 changes: 14 additions & 0 deletions examples/redux/public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Found Redux Example</title>
</head>

<body>
<div id="root"></div>
</body>

</html>
132 changes: 132 additions & 0 deletions examples/redux/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import React from 'react';
import ReactDOM from 'react-dom';
import FarceActions from 'farce/lib/Actions';
import BrowserProtocol from 'farce/lib/BrowserProtocol';
import createHistoryEnhancer from 'farce/lib/createHistoryEnhancer';
import queryMiddleware from 'farce/lib/queryMiddleware';
import createConnectedRouter from 'found/lib/createConnectedRouter';
import createMatchEnhancer from 'found/lib/createMatchEnhancer';
import createRender from 'found/lib/createRender';
import foundReducer from 'found/lib/foundReducer';
import Matcher from 'found/lib/Matcher';
import resolveElements from 'found/lib/resolveElements';
import Redirect from 'found/lib/Redirect';
import Link from 'found/lib/Link';
import { Provider } from 'react-redux';
import { combineReducers, compose, createStore } from 'redux';

function LinkItem(props) {
// TODO: Remove the pragma once evcohen/eslint-plugin-jsx-a11y#81 ships.
return (
<li>
<Link // eslint-disable-line jsx-a11y/anchor-has-content
{...props}
activeStyle={{ fontWeight: 'bold' }}
/>
</li>
);
}

const propTypes = {
children: React.PropTypes.node,
};

function App({ children }) {
return (
<div>
<ul>
<LinkItem to="/">
Main
</LinkItem>
<ul>
<LinkItem to="/foo">
Foo
</LinkItem>
<LinkItem to="/bar">
Bar (async)
</LinkItem>
<LinkItem to="/baz">
Baz (redirects to Foo)
</LinkItem>
<LinkItem to="/qux">
Qux (missing)
</LinkItem>
</ul>
</ul>

{children}
</div>
);
}

App.propTypes = propTypes;

const routeConfig = [
{
path: '/',
Component: App,
children: [
{
Component: () => <div>Main</div>,
},
{
path: 'foo',
Component: () => <div>Foo</div>,
},
{
path: 'bar',
getComponent: () => new Promise((resolve) => {
setTimeout(resolve, 1000, ({ data }) => <div>{data}</div>);
}),
getData: () => new Promise((resolve) => {
setTimeout(resolve, 1000, 'Bar');
}),
render: ({ Component, props }) => ( // eslint-disable-line react/prop-types
Component && props ? (
<Component {...props} />
) : (
<div><small>Loading&hellip;</small></div>
)
),
},
new Redirect({
from: 'baz',
to: '/foo',
}),
],
},
];

const store = createStore(
combineReducers({
found: foundReducer,
}),
compose(
createHistoryEnhancer({
protocol: new BrowserProtocol(),
middlewares: [queryMiddleware],
}),
createMatchEnhancer(
new Matcher(routeConfig),
),
),
);

store.dispatch(FarceActions.init());

const ConnectedRouter = createConnectedRouter({
render: createRender({
renderError: ({ error }) => ( // eslint-disable-line react/prop-types
<div>
{error.status === 404 ? 'Not found' : 'Error'}
</div>
),
}),
});

ReactDOM.render(
<Provider store={store}>
<ConnectedRouter resolveElements={resolveElements} />
</Provider>,
document.getElementById('root'),
);
15 changes: 15 additions & 0 deletions examples/universal-redux/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Found Universal Redux Example

This example uses the same route configuration as the [basic JSX
example](../basic-jsx), but uses server-side rendering for the initial page
load and a custom redux store. The redux store is initially populated on the
server and then the client rehydrates itself with the server's state.

## Usage

```
$ npm i
$ npm start
```

Then open [http://localhost:3000/](http://localhost:3000/) in your browser.
24 changes: 24 additions & 0 deletions examples/universal-redux/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "universal-redux",
"version": "0.1.0",
"private": true,
"scripts": {
"start": "babel-node src/server"
},
"dependencies": {
"babel-cli": "^6.23.0",
"babel-loader": "^6.3.0",
"babel-preset-latest": "^6.22.0",
"babel-preset-react": "^6.23.0",
"express": "^4.14.1",
"farce": "^0.2.1",
"found": "../..",
"react": "^15.4.2",
"react-dom": "^15.4.2",
"react-redux": "^5.0.2",
"redux": "^3.6.0",
"serialize-javascript": "^1.3.0",
"webpack": "^2.2.1",
"webpack-dev-middleware": "^1.10.0"
}
}
50 changes: 50 additions & 0 deletions examples/universal-redux/src/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from 'react';
import Link from 'found/lib/Link';

function LinkItem(props) {
// TODO: Remove the pragma once evcohen/eslint-plugin-jsx-a11y#81 ships.
return (
<li>
<Link // eslint-disable-line jsx-a11y/anchor-has-content
{...props}
activeStyle={{ fontWeight: 'bold' }}
/>
</li>
);
}

const propTypes = {
children: React.PropTypes.node,
};

function App({ children }) {
return (
<div>
<ul>
<LinkItem to="/">
Main
</LinkItem>
<ul>
<LinkItem to="/foo">
Foo
</LinkItem>
<LinkItem to="/bar">
Bar (async)
</LinkItem>
<LinkItem to="/baz">
Baz (redirects to Foo)
</LinkItem>
<LinkItem to="/qux">
Qux (missing)
</LinkItem>
</ul>
</ul>

{children}
</div>
);
}

App.propTypes = propTypes;

export default App;
34 changes: 34 additions & 0 deletions examples/universal-redux/src/client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from 'react';
import ReactDOM from 'react-dom';
import createConnectedRouter from 'found/lib/createConnectedRouter';
import getStoreRenderArgs from 'found/lib/getStoreRenderArgs';
import resolveElements from 'found/lib/resolveElements';
import { Provider } from 'react-redux';
import { BrowserProtocol } from 'farce';

import render from './render';
import genStore from './genStore';

// eslint-disable-next-line no-underscore-dangle
const store = genStore(new BrowserProtocol(), window.__PRELOADED_STATE__);
const matchContext = { store };
const ConnectedRouter = createConnectedRouter({ render });

(async () => {
const initialRenderArgs = await getStoreRenderArgs({
store,
matchContext,
resolveElements,
});

ReactDOM.render(
<Provider store={store}>
<ConnectedRouter
matchContext={matchContext}
resolveElements={resolveElements}
initialRenderArgs={initialRenderArgs}
/>
</Provider>,
document.getElementById('root'),
);
})();
30 changes: 30 additions & 0 deletions examples/universal-redux/src/genStore.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import {
createHistoryEnhancer,
queryMiddleware,
} from 'farce';
import createMatchEnhancer from 'found/lib/createMatchEnhancer';
import foundReducer from 'found/lib/foundReducer';
import Matcher from 'found/lib/Matcher';
import { combineReducers, compose, createStore } from 'redux';

import routeConfig from './routeConfig';

export default function genStore(historyProtocol, preloadedState) {
const store = createStore(
combineReducers({
found: foundReducer,
}),
preloadedState,
compose(
createHistoryEnhancer({
protocol: historyProtocol,
middlewares: [queryMiddleware],
}),
createMatchEnhancer(
new Matcher(routeConfig),
),
),
);

return store;
}
10 changes: 10 additions & 0 deletions examples/universal-redux/src/render.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react';
import createRender from 'found/lib/createRender';

export default createRender({
renderError: ({ error }) => ( // eslint-disable-line react/prop-types
<div>
{error.status === 404 ? 'Not found' : 'Error'}
</div>
),
});
40 changes: 40 additions & 0 deletions examples/universal-redux/src/routeConfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React from 'react';
import Redirect from 'found/lib/Redirect';

import App from './App';

export default [
{
path: '/',
Component: App,
children: [
{
Component: () => <div>Main</div>,
},
{
path: 'foo',
Component: () => <div>Foo</div>,
},
{
path: 'bar',
getComponent: () => new Promise((resolve) => {
setTimeout(resolve, 1000, ({ data }) => <div>{data}</div>);
}),
getData: () => new Promise((resolve) => {
setTimeout(resolve, 1000, 'Bar');
}),
render: ({ Component, props }) => ( // eslint-disable-line react/prop-types
Component && props ? (
<Component {...props} />
) : (
<div><small>Loading&hellip;</small></div>
)
),
},
new Redirect({
from: 'baz',
to: '/foo',
}),
],
},
];
Loading

0 comments on commit f094b36

Please sign in to comment.