来自 JSON 的 React 组件的动态布局

Tro*_*son 6 javascript reactjs

我正在编写一个反应应用程序,它是金融交易应用程序的瘦客户端 UI。一个核心要求是应用程序是完全动态和可配置的,包括表单。具体来说,我有需要在服务器端定义并存储在数据库中以在客户端动态呈现的交易输入表单,但布局很重要并且需要能够支持多种不同的格式。我见过一些采用 JSON 形式模式并从中创建静态形式的库,但它们似乎都不支持我需要的那种布局灵活性。例如,我需要支持组件的选项卡、列和行。我的问题是 - 任何人都可以推荐一个可以做我正在寻找的东西的 ReactJs 库吗?如果没有,我该如何自己实施?

这是一个更具体的例子;假设我有一个通过 REST 调用从服务器获取的架构,如下所示:

{
title: "Securities Finance Trade Entry",
children: [
 {
   containerType: "tabs",
   children: [
      {
          title: "Common",
          children: [
             {
                containerType: "row", 
                children: [
                  {
                    input: "ComboBox",
                    label: "Trade Type",
                    options: ["Repo", "Buy/Sell", "FeeBased"]
                  },
                  {
                    input: "ComboBox",
                    label: "Direction",
                    options: ["Loan", "Borrow"]
                  }
                ]
             },
             {
               containerType: "row",
               children: [
                 {
                    containerType: "column",
                    children: [
                      {
                        containerType: "row",
                        children: [
                          {
                            input: "text",
                            label: "Book"
                          },
                          {
                            input: "text",
                            label: "Counterparty"
                          }
                        ]
                      },
                      {
                        containerType: "row",
                        children: [
                          {
                            input: "date",
                            label: "StartDate"
                          },
                          {
                            input: "date",
                            label: "EndDate"
                          }
                        ]
                      },
                      {
                        containerType: "row",
                        children: [
                          {
                            input: "text",
                            label: "Security"
                          },
                          {
                            input: "numeric",
                            label: "Quantity"
                          }
                        ]
                      }
                    ]
                 }
               ]
             }
          ]
      }
   ]
 }
]
} 
Run Code Online (Sandbox Code Playgroud)

我希望呈现如下内容: 在此处输入图片说明 基本上在该模式中,只会显示一个选项卡,但可能有多个选项卡,每个选项卡在行和列中包含多个子项,也可能包含嵌套的选项卡容器。如果我自己在 react 中渲染它,我会考虑使用 .map 来遍历 json 和一些 if 语句以在适当的地方插入标签。但是,项目需要嵌套,所以我不知道如何呈现它,以便选择的标签是动态的并且可以有子项......例如我可以写:{ if (container.containerType === "column" ) { () } 但是后来我需要在该标签中嵌入其余的控件,我认为我不能在最后发出一个 () ......

我考虑过的另一个选择是在服务器端将上述 json 转换为 JSX 并发送。在 Java 服务器端编写一个解析器将上述 json 转换为 JSX 文档并将其返回给客户端是相当容易的,但是我将如何呈现它呢?有什么办法可以做类似的事情:

onComponentMount() {
   fetch(webserviceUrl + 'getJsxForForm/' + props.formName)
   .then(result => {this.setState({form : result});
}
render()  {
   return ({this.state.form});
}
Run Code Online (Sandbox Code Playgroud)

但同样,我认为这行不通。如果我从服务器获取文档,它会将它呈现为纯文本,而不是实际将其转换为有效的 html,对吗?

那么,我有哪些选择?我正在寻找可以执行此操作的现有库的建议,或者关于我提到的其他两种方法中的任何一种的建议(它们会起作用吗?我该怎么做?),或者替代想法。谢谢,特洛伊

wlh*_*wlh 4

我喜欢通过某种 JSON 配置动态渲染页面的概念。

关键是定义Components匹配containerTypesinputs然后JSON通过递归函数遍历您的配置。在您的JSON配置中,我建议在您想要呈现组件的任何地方使用组件命名约定。因此,大写TabsRowColumn

下面是该函数的一个示例。请注意,在每个containerType组件中都会调用此函数并children传入。

请参阅这支笔:https://codepen.io/wesleylhandy/pen/oQaExK/

示例组件:

const Container = props => {
    return (
        <div className="container">
            <h1>{props.title}</h1>
            {renderChildren(props.children)}
        </div>
    )  
 }
Run Code Online (Sandbox Code Playgroud)

儿童的递归渲染示例

const renderChildren = children => {

    return children ? children.map((child, ind) => {
        const newChildren = child.children ? [...child.children] : [];
        const {containerType, title, input, label, options} = child
        let key;

        if (newChildren.length) {
            key = `${containerType}-${ind}`;
            switch (containerType) {
                case "Tabs":
                    return <Tabs 
                        key={key} 
                        title={title} 
                        children={newChildren}
                    />
                case "Column":
                    return <Column 
                        key={key} 
                        title={title} 
                       children={newChildren}
                    />
                case "Row":
                      return <Row 
                      key={key} 
                      title={title} 
                      children={newChildren}
                   /> 
                default:
                    return <Common 
                        key={key} 
                        title={title} 
                        children={newChildren}
                    />    
            }
        } else {
            key=`${input}-${ind}`
            switch (input) {
                case "ComboBox":
                    return <SelectGroup
                        key={key}
                        label={label}
                        options={options}
                   />
               case "Text":
               case "Date":
               case "Numeric":
                   return <InputGroup
                       key={key}
                       label={label}
                       type={input}
                   />           
           }
       }
   }) : null
}
Run Code Online (Sandbox Code Playgroud)