【问题标题】:What is the most efficient way of rendering a n-level nested object in React JS?在 React JS 中渲染 n 级嵌套对象的最有效方法是什么?
【发布时间】:2020-02-15 10:27:02
【问题描述】:

我有一个来自 API 的数据如下 -

{
  "expression": [
    "a",
    "b"
  ],
  "groups": [
    {
      "expression": [

      ],
      "groups": [
        {
          "expression": [
            "c",
            "d"
          ],
          groups: null
        }
      ]
    },
    {
      "expression": [
        "p",

      ],
      groups: null
    }
  ]
}

我必须渲染表达式和组(也包括表达式和多个组)。构建块是一个表达式。我们需要将嵌套表达式显示为组。

我尝试了递归函数调用,但对于深度较大的对象来说,这并没有太大的效率。

这是和我的试验类似的东西 -

let conditionStack = [];
  function parseInnerConditions(conditionObj) {
    if (conditionObj.expression) {
      conditionObj.expression.map((each, index) => {
        conditionStack = [
          ...conditionStack,
          <NewExpression key={index} conditionExpression={each} />, //renders an expression
        ];
      });
    }
    if (conditionObj.groups && conditionObj.groups.length) {
      return conditionObj.groups.map((child, index) => {
        conditionStack = [
          ...conditionStack,
          <ConditionGroup key={index}> // renders a block or group of expressions
            {parseInnerConditions(child)}
          </ConditionGroup>,
        ];
      });
    }
    return conditionStack;
  }

  return (
    <div>
    parseInnerConditions(conditionObject)
    </div>
  )

提前致谢。

【问题讨论】:

    标签: javascript reactjs recursion nested-object


    【解决方案1】:

    您的 map() 回调没有 return 值,但在第二个 if 语句中,您将返回数组,因此当您递归到每个 @ 时,您最终会得到 [undefined, undefined, ...] 987654328@.

    要修复您的解决方案,请将您的 .map() 更改为 .forEach() 并删除 conditionObj.groups.map(...) 之前的 return 关键字。

    这里有一个更好的方法:

    function ConditionGroup ({ expression, groups }) {
      const conditionExpressions = useMemo(
        () => expression && expression.map(
          (value, index) => (
            <NewExpression key={index} conditionExpression={value} />
          )
        ),
        [expression]
      );
      const conditionGroups = useMemo(
        () => groups && groups.map(
          (value, index) => (
            <ConditionGroup key={index} {...value} />
          )
        ),
        [groups]
      );
    
      return (
        <div>
          {conditionExpressions}
          {conditionGroups}
        </div>
      );
    }
    

    请注意,使用index 作为keyantipattern。理想情况下,如果您提供了一个唯一的 ID,您将希望使用一个唯一的 ID。有关这方面的更多信息,请参阅ReactJS : What is the best way to give keys in array element

    【讨论】:

    • 嗨,我尝试了使用“useMemo”的方法并遇到以下错误 - 未捕获的类型错误:nextCreate 不是 mountMemo 的函数 (react-dom.development.js?61bb:13459)
    • 我修复了这个问题,useMemo(()=> , []) - 这应该是 useMemo 的正确语法。但是非常感谢。您的解决方案非常适合我们的用例。
    • @SaikatBhattacharya 感谢您指出这一点,我现在修复了我的示例。
    • @Patrik 在实现此功能后我面临一个问题 - conditionExpressions 实际上是一个具有一个输入字段和一个下拉列表的表单。对于嵌套在组中的conditionExpressions,每当我尝试输入输入框时,我输入的每个字母都会失去焦点。知道可能是什么问题吗?
    【解决方案2】:

    ReactJS 是一个基于组件的 库,用于生成 UI。因此,就组件而言,您的数据是一个组,该组又将包含一个表达式和其他类似的组。分解它,我们可以形成三个组件:

    1. Expression 用于简单地渲染组中的表达式。
    2. Group 用于渲染组。
    3. Groups 用于提取 Group 组件,然后为数据中的其他渲染。

    这是一个示例代码:

    Index.js这是从API获取数据的文件。

    import React from "react";
    import Group from "./Group";
    
    const data = {
      expression: ["a", "b"],
      groups: [
        {
          expression: [],
          groups: [{ expression: ["c", "d"], groups: null }]
        },
        {
          expression: [],
          groups: [
            { expression: ["e", "f"], groups: null },
            { expression: ["g", "h"], groups: null }
          ]
        },
        {
          expression: ["p"],
          groups: null
        }
      ]
    };
    const stage = 1;
    const Main = () => {
      return (
        <div>
          <Group data={data} stage={stage} />
        </div>
      );
    };
    
    export default Main;
    

    Group.js 用于渲染组。

    import React from "react";
    import Expression from "./Expressions";
    import Groups from "./Groups";
    
    const populateGroup = (data, stage) => {
      const HTML = [];
      for (const x in data) {
        if (x === "expression") {
          HTML.push(<Expression expression={data[x]} />);
        }
        if (x === "groups") {
          HTML.push(<Groups data={data[x]} stage={stage} />);
        }
      }
      return HTML;
    };
    
    const Group = ({ data, stage }) => {
      return (
        <div>
          <p>{`Group @ Stage ${stage}`}</p>
          <ol className="Group">{populateGroup(data, stage + 1).map(el => el)}</ol>
        </div>
      );
    };
    
    export default Group;
    

    Expression.js 用于简单地在组中呈现表达式。

    import React from "react";
    
    const Expression = ({ expression }) => {
    
    return (
        <div className="expression">
          {expression.map(term => (
            <h3 style={{ display: "inline" }}>{term}</h3>
          ))}
        </div>
      );
    };
    
    export default Expression;
    
    

    Groups.js 用于提取然后渲染Group 组件。

    import React from "react";
    import Group from "./Group";
    
    const Groups = ({ data, stage }) => {
    
      if (data === null) return <span></span>;
    
      return (
        <div className="GroupsSection">
          {data.map((section, i) => (
            <Group key={i} data={section} stage={stage} />
          ))}
        </div>
      );
    };
    
    export default Groups;
    
    

    性能 使用这种基于组件的方法,数据被分块,这应该会提高性能以获得更好的结果,for...inmap 可以替换为for 循环。 Sample Render

    【讨论】:

      猜你喜欢
      • 2021-10-28
      • 1970-01-01
      • 2015-04-02
      • 2019-08-01
      • 2020-05-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多