Skip to content

Commit

Permalink
Refactor and update API
Browse files Browse the repository at this point in the history
* Use createElement instead of root route
* Support per-route render callbacks
  • Loading branch information
taion committed Aug 27, 2015
1 parent f02b161 commit 0a6f7b3
Show file tree
Hide file tree
Showing 15 changed files with 404 additions and 238 deletions.
3 changes: 2 additions & 1 deletion .babelrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"stage": 0,
"loose": "all"
"loose": "all",
"optional": ["runtime"]
}
3 changes: 0 additions & 3 deletions .eslintignore

This file was deleted.

15 changes: 1 addition & 14 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -1,16 +1,3 @@
{
"extends": "eslint-config-airbnb",
"env": {
"browser": true,
"mocha": true,
"node": true
},
"rules": {
"react/jsx-uses-react": 2,
"react/jsx-uses-vars": 2,
"react/react-in-jsx-scope": 2
},
"plugins": [
"react"
]
"extends": "airbnb"
}
Empty file modified LICENSE.md
100755 → 100644
Empty file.
72 changes: 52 additions & 20 deletions README.md
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,49 +1,81 @@
relay-nested-routes
react-router-relay
=========================
Nested react-router views for Relay
Nested react-router routes for Relay

$ npm install --save relay-nested-routes
$ npm install --save react-router-relay

After you've installed it, add it as a root `<Route>` to your
react-router@>=1.0.0-beta3 routes like so:
Afterwards, add it as the `createElement` of your react-router@>=1.0.0-beta3
`<Router>` like so:

```js
import React from 'react';
import ReactDOM from 'react-dom';
import Relay from 'react-relay';
import { Router, Route } from 'react-router';

import RelayNestedRoutes from 'relay-nested-routes';
var NestedRootContainer = RelayNestedRoutes(React, Relay);
import ReactRouterRelay from 'react-router-relay';

/* ... */

ReactDOM.render((
<Router history={new BrowserHistory()}>
<Route component={NestedRootContainer}>
<Route component={App} queries={AppQueries}>
<Route path="/" component={Dashboard} queries={DashboardQueries}/>
</Route>
<Router
history={new BrowserHistory()}
createElement={ReactRouterRelay.createElement}
>
<Route component={App} queries={AppQueries}>
<Route path="/" component={Dashboard} queries={DashboardQueries}/>
</Route>
</Router>
), document.getElementById('react-root'));
```

Define an object containing your queries that a particular `Relay.Container`
needs and add it as a `queries` prop to any container `<Route/>`s.
needs and add it as a `queries` prop to any container `<Route/>`s:

```js
var AppQueries = {
viewer: (Component) => Relay.QL`
viewer {
${Component.getFragment('viewer')}
}
`
};
```

`relay-nested-routes` will automatically generate a component that includes all
`react-router-relay` will automatically generate a component that includes all
of your fragments, and a route that includes all of your root queries,
and dispatch/render everything in one go.

You can also pass props like `renderLoading` by adding them as props to the
`NestedRootContainer` route.
# Render Callbacks

You can pass in custom `renderLoading`, `renderFetched`, and `renderFailure`
callbacks to your routes:

```js
<Route {/* ... */} renderLoading={() => <Loading />} />
```

These have the same signature and behavior as they do on `Relay.RootContainer`,
except that the argument to `renderFetched` also includes the injected props
from React Router. As on `Relay.RootContainer`, the `renderLoading` callback
can simulate the default behavior of rendering the previous view by returning
`undefined`.

# Todo
# Query Parameters

* Named react-router components
You can pass an array to the `queryParams` prop to specify which query
parameters should be passed in from the router and made available as
variables to your root queries and containers:

```js
<Route
path='/widgets'
component={Widgets}
queries={WidgetsQueries}
queryParams={['date', 'color']} // date and color will be passed as variables
/>`
```

# Thanks
# Special Thanks

[@cpojer](https://github.com/cpojer)

Expand Down
33 changes: 18 additions & 15 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
{
"name": "relay-nested-routes",
"version": "0.3.1",
"description": "Nested react-router views for Relay",
"name": "react-router-relay",
"version": "0.4.0",
"description": "Nested react-router routes for Relay",
"files": [
"lib",
"LICENSE",
"README.md"
],
"main": "lib/index.js",
"scripts": {
"clean": "rimraf lib dist",
"clean": "rimraf lib",
"build": "babel src --out-dir lib",
"lint": "eslint src test examples",
"lint": "eslint src",
"prepublish": "npm run clean && npm run build"
},
"repository": {
Expand All @@ -27,18 +32,16 @@
"homepage": "https://github.com/devknoll/relay-nested-routes",
"devDependencies": {
"babel": "^5.5.8",
"babel-core": "^5.6.18",
"babel-eslint": "^3.1.15",
"babel-loader": "^5.1.4",
"eslint": "^0.23",
"eslint-config-airbnb": "0.0.6",
"eslint-plugin-react": "^2.3.0",
"rimraf": "^2.3.4",
"webpack": "^1.9.6",
"webpack-dev-server": "^1.8.2"
"babel-eslint": "^4.0.10",
"eslint": "^1.2",
"eslint-config-airbnb": "0.0.8",
"eslint-plugin-react": "^3.2.3",
"react": "^0.14.0-beta3",
"react-router": "^1.0.0-beta3",
"rimraf": "^2.3.4"
},
"dependencies": {
"invariant": "^2.1.0",
"warning": "^2.0.0"
"react-static-container": "^1.0.0-alpha.1"
}
}
85 changes: 85 additions & 0 deletions src/Container.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import React from 'react';
import StaticContainer from 'react-static-container';

import getParamsForRoute from './getParamsForRoute';
import RootComponent from './RootComponent';
import RouteAggregator from './RouteAggregator';

export default class Container extends React.Component {
static displayName = 'ReactRouterRelay.Container';

static propTypes = {
Component: React.PropTypes.func.isRequired,
routerProps: React.PropTypes.object.isRequired,
};

static contextTypes = {
routeAggregator: React.PropTypes.instanceOf(RouteAggregator),
};

render() {
const {routeAggregator} = this.context;
if (!routeAggregator) {
return <RootComponent {...this.props} />;
}

const {Component, routerProps} = this.props;
const {route} = routerProps;

// FIXME: Remove once fix for facebook/react#4218 is released.
const {children} = routerProps;
if (children) {
routerProps.children = React.cloneElement(children, {});
}

const {queries} = route;
if (!queries) {
return <Component {...routerProps} />;
}

const params = getParamsForRoute(routerProps);
const {fragmentPointers, failure} =
routeAggregator.getData(queries, params);

let shouldUpdate = true;
let element;

// This is largely copied from RelayRootContainer#render.
if (failure) {
const {renderFailure} = route;
if (renderFailure) {
const [error, retry] = failure;
element = renderFailure(error, retry);
} else {
element = null;
}
} else if (fragmentPointers) {
const data = {...routerProps, ...params, ...fragmentPointers};

const {renderFetched} = route;
if (renderFetched) {
element = renderFetched(data);
} else {
element = <Component {...data} />;
}
} else {
const {renderLoading} = route;
if (renderLoading) {
element = renderLoading();
} else {
element = undefined;
}

if (element === undefined) {
element = null;
shouldUpdate = false;
}
}

return (
<StaticContainer shouldUpdate={shouldUpdate}>
{element}
</StaticContainer>
);
}
}
25 changes: 0 additions & 25 deletions src/NestedRenderer.js

This file was deleted.

70 changes: 70 additions & 0 deletions src/RootComponent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import React from 'react';
import Relay from 'react-relay';

import Container from './Container';
import RouteAggregator from './RouteAggregator';

export default class RootComponent extends React.Component {
static displayName = 'ReactRouterRelay.RootComponent';

static propTypes = {
routerProps: React.PropTypes.object.isRequired,
};

static childContextTypes = {
routeAggregator: React.PropTypes.instanceOf(RouteAggregator).isRequired,
};

constructor(props, context) {
super(props, context);

this._routeAggregator = new RouteAggregator();
this._routeAggregator.updateRoute(props.routerProps);
}

getChildContext() {
return {
routeAggregator: this._routeAggregator,
};
}

componentWillReceiveProps(nextProps) {
const {routerProps} = nextProps;
if (routerProps.isTransitioning) {
return;
}

this._routeAggregator.updateRoute(routerProps);
}

renderLoading = () => {
this._routeAggregator.setLoading();
return this.renderComponent();
};

renderFetched = (data) => {
this._routeAggregator.setFetched(data);
return this.renderComponent();
};

renderFailure = (error, retry) => {
this._routeAggregator.setFailure(error, retry);
return this.renderComponent();
};

renderComponent() {
return <Container {...this.props} />;
}

render() {
return (
<Relay.RootContainer
Component={this._routeAggregator}
route={this._routeAggregator.route}
renderLoading={this.renderLoading}
renderFetched={this.renderFetched}
renderFailure={this.renderFailure}
/>
);
}
}
Loading

0 comments on commit 0a6f7b3

Please sign in to comment.