React-router: Non-JSX examples

Created on 24 Nov 2014  Â·  19Comments  Â·  Source: ReactTraining/react-router

It would be great if there could be some examples using regular js syntax, it's sometimes hard to know what the different classes return and how they're supposed to be used after the latest update.

Most helpful comment

The way I understand it, and as mjackson pointed out, createFactory merely allows you to use plain function calls like you did before React 0.12, allowing for cleaner code and easier migration (just add createFactory to your imports, instead of adding createElement to every component you render).
Using both createFactory and createElement, or neither, will lead to warnings.

Example:

// jsx
var React = require('react');
var Router = require('react-router');
var Route = Router.Route;
var DefaultRoute = Router.DefaultRoute;

var routes = (
  <Route name="contacts" path="/" handler={App}>
    <DefaultRoute name="index" handler={Index}/>
    <Route name="contact" path="contact/:id" handler={Contact}/>
  </Route>
);

// createElement / converted jsx
var React = require('react');
var Router = require('react-router');
var Route = Router.Route;
var DefaultRoute = Router.DefaultRoute;

var routes = (
  React.createElement(Route, {name: "contacts", path: "/", handler: App}, 
    React.createElement(DefaultRoute, {name: "index", handler: Index}), 
    React.createElement(Route, {name: "contact", path: "contact/:id", handler: Contact})
  )
);

// using createFactory
var React = require('react');
var Router = require('react-router');
var Route = React.createFactory(Router.Route);
var DefaultRoute = React.createFactory(Router.DefaultRoute);

var routes = (
    Route({name: "contacts", path: "/", handler: App},
        DefaultRoute({name: "index", handler: Index}),
        Route({name: "contact", path: "contact/:id", handler: Contact})
    )
);

According to this I think the recommended way for plain JS is to use createFactory for imported components, and createElement for "dynamic components", e.g. the Handler component passed through Router.run.

As for passing your handler components, you shouldn't use either createFactory or createElement, since react-router uses createElement on them and therefore expects a plain class.

All 19 comments

I think the JSX makes it clear which pieces are components, and which are not.

Router.run(routes, function(Handler) {
  React.render(<Handler/>, document.body);
  // v
  React.render(React.createElement(Handler, {}), document.body);
});

What do you have in mind?

Not sure, maybe I was just having a bad case of the Monday but it took me a wee bit too long to figure it out. Small examples like the one above would have saved me some time.

I'm also getting a lot of "Warning: This JSX uses a plain function. Only React components are valid in React's JSX transform." logs. Not entirely sure where it comes from but it feels like it also stems from a not super obvious JSX/non-JSX mix match.

I'm still unclear on ... what is unclear.

What objects in react router are you confused about being components or not?

@Chrazy You're not seeing that warning because of anything we're doing. We eliminated all those warnings in the 0.11 release we made earlier this week.

Most likely you have some components that you aren't wrapping in JSX/factories, e.g.

var MyComponent = require('./MyComponent');

// in React 0.10 you could do this:
render: function () {
  return MyComponent();
}

// but React 0.12 forces you to do it like this (hint: JSX does this for you):
render: function () {
  return React.createElement(MyComponent);
}

// alternatively, you can create a "factory" and then use that to create elements
var MyComponentFactory = React.createFactory(MyComponent);

render: function () {
  return MyComponentFactory();
}

Re: "Warning: This JSX uses a plain function. Only React components are valid in React's JSX transform." if anyone else gets the same thing and are slow like me. :)

It happens when you call createElement on a factory. So if you do this it will warn.

var MyComponent = React.createFactory require('./MyComponent');

var routes = … //Something with MyComponent as handler

Router.run(routes, function(Handler) {
  React.render(React.createElement(Handler, {}), document.body);
});

It turns out that you shouldn't use createFactory or createElement to get rid of the warnings. Not sure where the transformation occurs but this isn't the obvious way to use this at all. So I definitely think some documentation could be of help.

Yes, I'm having some problems as well, simple working example without JSX would help a lot :)

@Chrazy We don't use createFactory anywhere in our documentation. Where did you get the idea that you should use it with the router?

I'm happy to make changes to our docs, but I can't find where they're misleading you.

@mjackson I think one simple example without JSX would be all that we need! :)

Since all composite components have to be wrapped I didn't even consider not wrapping the handlers, so used to doing it these days. As @szymonkaliski wrote, just some simple examples would have made the transition easier.

The way I understand it, and as mjackson pointed out, createFactory merely allows you to use plain function calls like you did before React 0.12, allowing for cleaner code and easier migration (just add createFactory to your imports, instead of adding createElement to every component you render).
Using both createFactory and createElement, or neither, will lead to warnings.

Example:

// jsx
var React = require('react');
var Router = require('react-router');
var Route = Router.Route;
var DefaultRoute = Router.DefaultRoute;

var routes = (
  <Route name="contacts" path="/" handler={App}>
    <DefaultRoute name="index" handler={Index}/>
    <Route name="contact" path="contact/:id" handler={Contact}/>
  </Route>
);

// createElement / converted jsx
var React = require('react');
var Router = require('react-router');
var Route = Router.Route;
var DefaultRoute = Router.DefaultRoute;

var routes = (
  React.createElement(Route, {name: "contacts", path: "/", handler: App}, 
    React.createElement(DefaultRoute, {name: "index", handler: Index}), 
    React.createElement(Route, {name: "contact", path: "contact/:id", handler: Contact})
  )
);

// using createFactory
var React = require('react');
var Router = require('react-router');
var Route = React.createFactory(Router.Route);
var DefaultRoute = React.createFactory(Router.DefaultRoute);

var routes = (
    Route({name: "contacts", path: "/", handler: App},
        DefaultRoute({name: "index", handler: Index}),
        Route({name: "contact", path: "contact/:id", handler: Contact})
    )
);

According to this I think the recommended way for plain JS is to use createFactory for imported components, and createElement for "dynamic components", e.g. the Handler component passed through Router.run.

As for passing your handler components, you shouldn't use either createFactory or createElement, since react-router uses createElement on them and therefore expects a plain class.

If people don't want to use JSX, they don't have to, but they do have to learn how, I'm going to keep using JSX in the docs.

An example without JSX that also has route nesting:

// this snippet was tested with react 0.13.1 
// and react-router 0.13.2
import Router from 'react-router';
import App    from './components/App';
import Inbox  from './components/Inbox';

const AppRoute = Router.createRoute({
  path: '/',
  name: 'app',
  handler: App
});

const InboxRoute = Router.createRoute({
  name: 'inbox',
  handler: Inbox,
  parentRoute: AppRoute
});

// Important: you have to export the root route wrapped in array 
export default [AppRoute];

+1 for showing how to create routes without JSX.

As someone coming from History.js, Backbone.js, and Ember.js background, I would rather write my routes using JS instead of writing them as JSX markup. Thank you @gryzzly for the example.

Is it possible to create routes dynamically in jsx?

Watched the talk @mjackson gave at ReactEurope and he mentioned a new declarative non-JSX interface to the router in 1.0. Are there any docs available for this yet?

@contra the v1.0.0-beta3 docs have a short section on plain routes.

Is there a way to do the same implementation than the Pinterest example but using JSX ?

In the documentation, it's written

A route configuration object. Router turns JSX s into these objects, but you can use them directly if you prefer. All of the props are the same as props, except those listed here.

Does that means there is no way to use getChildRoutes in JSX ?

PS : may be I should open another issue for that ?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

sarbbottam picture sarbbottam  Â·  3Comments

ArthurRougier picture ArthurRougier  Â·  3Comments

maier-stefan picture maier-stefan  Â·  3Comments

davetgreen picture davetgreen  Â·  3Comments

jzimmek picture jzimmek  Â·  3Comments