ph34r ph34r - 3 months ago 24
JSON Question

Dynamically Define ReactJS Routes from JSON

I have a global JSON configuration that has a variety of configuration data, including route names and the components that I'd like to be rendered for the route. I'd like to dynamically build my routes from this JSON configuration. I'm currently able to dynamically generate the route, however, since the route components are Strings in the JSON file, React doesn't like them and throws the error below. Any suggestions for accomplishing this goal?

warning.js:44 Warning: Unknown props `history`, `location`, `params`, `route`, `routeParams`, `routes` on <Dashboard> tag. Remove these props from the element. For details, see https://f b.me/react-unknown-prop
in Dashboard
in RouterContext
in Router


Relevant JSON snippet:

{
"routes" : [
{
"route_name" : "home",
"path" : "/",
"visible_in_menu" : true,
"menu_title" : "Home",
"menu_font_awesome_icon" : "fa fa-home",
"component" : "App",
"child_routes" : null
},
{
"route_name" : "analytics",
"path" : "/analytics",
"visible_in_menu" : true,
"menu_title" : "Analytics",
"menu_font_awesome_icon" : "fa fa-bar-chart",
"component" : "Dashboard",
"template" : null,
"child_routes" : [
{
"route_name" : "analytics_daily" ,
"path" : "/daily",
"visible_in_menu" : true,
"menu_title" : "Daily",
"component" : "Dashboard"
}
]
}
]
}


Code to fetch config and dynamically build the routes:

import React from 'react';
import ReactDOM from 'react-dom';
import { Router, Route, Link, browserHistory } from 'react-router'
import $ from 'jquery';

import App from './App';
import Dashboard from './Dashboard';
import SidebarMenu from './SidebarMenu';

import './index.css';

$.get("/routes_menu_config.json", bootstrapApplication);

function bootstrapApplication(config){

var dynamicRoutesJSX = buildDynamicRoutes(config);

// Add dynamic routes to app
ReactDOM.render((
<Router history={browserHistory}>
{dynamicRoutesJSX}
</Router>
), document.getElementById('root'));

// Render sidebar menu
ReactDOM.render(
<SidebarMenu />,
document.getElementById('menu')
);

}

function buildDynamicRoutes(config){

var routeJSX = [];

for (let [index, route] of config.routes.entries()) {
routeJSX.push(<Route path={route.path} components={route.component} key={index}/>);
}

return routeJSX;
}


I also tried the plain object instantiation of routes instead of using JSX, but it produces the same error:

$.get("/routes_menu_config.json", bootstrapApplication);

function bootstrapApplication(config){

var dynamicRoutesJSX = buildDynamicRoutes(config);

// Add dynamic routes to app
ReactDOM.render(<Router history={browserHistory} routes={dynamicRoutesJSX}

// Render sidebar menu
ReactDOM.render(
<SidebarMenu />,
document.getElementById('menu')
);

}


function buildDynamicRoutes(config){

var routes = [];

// Iterate parent routes from config
for (var i=0; i<config.routes.length; i++) {

var configParentRouteDefinition = config.routes[i];

// Create parent route definition
var parentRouteDefinition = {
path : configParentRouteDefinition.path,
component: configParentRouteDefinition.component
};

// If there are child routes, add them to the definition
if(configParentRouteDefinition.child_routes){

// Track child routes
var childRoutes = [];

// Iterate child routes, generate definition
for(var j=0; j<configParentRouteDefinition.child_routes.length; j++){

var configChildRouteDefinition = configParentRouteDefinition.child_routes[j]


var childRouteDefinition = {
path : configChildRouteDefinition.path,
component: configChildRouteDefinition.component
};

childRoutes.push(childRouteDefinition);
}

// Ad the definition to the parent route definition
parentRouteDefinition["childRoutes"] = childRoutes;

}

routes.push(parentRouteDefinition);

}

return routes;

}

Answer

You need to create a registry of components so that you can look up component references from their name:

import App from './App'; 
import Dashboard from './Dashboard';

const componentRegistry = {
    "App": App,
    "Dashboard": Dashboard
}

<Route path={route.path} components={componentRegistry[route.component]} key={index}/>;
Comments