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;
}
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}/>;
If you use e.g. Webpack it is possible without import all components to have result you want. However you have to pass path to the component rather the component's name. like so:
json file:
{"nav": [
{
"label": "HOME",
"route": {
"url": "/",
"exact": true
},
"component": {
"path": "home",
"name": "home"
}
}}
createRoutes() {
return this.props.data.nav.map((item: any, index: number) => {
let DynamicComponent = require('../../' + item.component.path + '/' + item.component.name).default;
return <Route key={index} path={item.route.url}
exact={item.route.exact}
render={() => (<DynamicComponent key={item.component.name}/>)}/>
});
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With