从 JSON 动态定义 ReactJS 路由

Posted

技术标签:

【中文标题】从 JSON 动态定义 ReactJS 路由【英文标题】:Dynamically Define ReactJS Routes from JSON 【发布时间】:2016-12-18 13:36:38 【问题描述】:

我有一个全局 JSON 配置,其中包含各种配置数据,包括路由名称和我希望为路由呈现的组件。我想从这个 JSON 配置动态构建我的路由。我目前能够动态生成路由,但是,由于路由组件是 JSON 文件中的字符串,React 不喜欢它们并抛出下面的错误。对实现这一目标有何建议?

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

相关JSON sn-p:


    "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"
                
            ]
        
    ]

获取配置并动态构建路由的代码:

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;

我也尝试了路由的普通对象实例化,而不是使用 JSX,但它产生了同样的错误:

$.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;


【问题讨论】:

【参考方案1】:

您需要创建一个组件注册表,以便您可以从它们的名称中查找组件引用:

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

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


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

【讨论】:

这行得通,谢谢。我希望有一种方法可以将字符串转换为实例化组件。 不幸的是,一个字符串告诉 React 渲染一个 html 节点,它不会在内部跟踪存在哪些组件,因此无法查找它们。【参考方案2】:

如果您使用例如Webpack 无需导入所有组件即可获得您想要的结果。但是,您必须将路径传递给组件,而不是组件的名称。像这样:

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/>)/>
    );

【讨论】:

【参考方案3】:

这个对我有用

App.tsx

import routes from "./routes";
const App: React.FC = () => 
  return (
      <BrowserRouter>
        <div>
          <Switch>
            routes.data.map((entry) => return (<Route ...entry/>))
          </Switch>
        </div>
      </BrowserRouter>
  );
;

export default App;

路由器.ts

const routes = data: [
        
            key: "one",
            path: "/three"

        ,
        
            key: "two",
            path: "/two"
        
    ]


export default routes;

【讨论】:

以上是关于从 JSON 动态定义 ReactJS 路由的主要内容,如果未能解决你的问题,请参考以下文章

ReactJS 中的动态路由到底是啥

ReactJS 中的参数路由不显示 UI 组件

react-route动态路由,它的子路由路径配置在啥地方

如何从定义在和/或动态 id 元素名称的 JS 类外部渲染 ReactJS 组件?

使用 GET 路由将变量从 ReactJS 前端传递到 NodeJS 后端

如何在 gatsby 中创建动态路由