【问题标题】:Recursive function in ReactjsReactjs 中的递归函数
【发布时间】:2020-06-21 07:35:08
【问题描述】:

我正在使用递归函数制作动态菜单,并且我已经制作了菜单,并且它以正确的顺序显示,没有任何问题。

我从 service.js 文件中收到菜单数据,您可以在下面的代码沙箱示例中看到整个工作应用程序,

https://codesandbox.io/s/reactstrap-accordion-3uoz9

要求:

这里我需要找出最后一级菜单,并需要将复选框分配为它们各自的 id {item.id}

例如:

对于第一个菜单一个

 -> [Checkbox with value as 1.1.1] One-One-One
 -> [Checkbox with value as 1.1.2] One - one - two
 -> [Checkbox with value as 1.1.3] One - one - three

对于第二个菜单两个

 -> [Checkbox with value as 2.1] Two - one

.

.

.

对于第六个菜单六个

 -> [Checkbox with value as 6] Six

我希望这一点很清楚,我需要找出递归的最后一层,并应为其分配一个带有其 id 值的复选框。

请fork提供的代码沙箱,帮我实现最后一层checkbox的效果。

可选要求: 如果可能的话,折叠会同时对整个菜单起作用,请使其在每个单独的级别上以唯一的方式折叠。

但主要的重要要求是在菜单的最后一级制作一个复选框。 提前非常感谢...

编辑:

正如 Crowder 所评论的,我已经创建了 sn-p 删除 reactstrap 代码,现在可以了,因为我需要显示复选框内联到子菜单的最新级别(最后一个子元素)。

const menuData = [
  {
    id: "1",
    name: "One",
    children: [
      {
        id: "1.1",
        name: "One - one",
        children: [
          { id: "1.1.1", name: "One - one - one" },
          { id: "1.1.2", name: "One - one - two" },
          { id: "1.1.3", name: "One - one - three" }
        ]
      }
    ]
  },
  {
    id: "2",
    name: "Two",
    children: [{ id: "2.1", name: "Two - one" }]
  },
  {
    id: "3",
    name: "Three",
    children: [
      {
        id: "3.1",
        name: "Three - one",
        children: [
          {
            id: "3.1.1",
            name: "Three - one - one",
            children: [
              {
                id: "3.1.1.1",
                name: "Three - one - one - one",
                children: [
                  { id: "3.1.1.1.1", name: "Three - one - one - one - one" }
                ]
              }
            ]
          }
        ]
      }
    ]
  },
  { id: "4", name: "Four" },
  {
    id: "5",
    name: "Five",
    children: [
      { id: "5.1", name: "Five - one" },
      { id: "5.2", name: "Five - two" },
      { id: "5.3", name: "Five - three" },
      { id: "5.4", name: "Five - four" }
    ]
  },
  { id: "6", name: "Six" }
];

class App extends React.Component {
  constructor(props) {
    super(props);


    this.state = {
      currentSelection: "",
      menuItems: [],
      isToggleOpen: false
    };
  }

  componentDidMount() {
    this.setState({ menuItems: menuData });
  }

  handleClick(id, evt) {
    evt.preventDefault();
    console.log("click handler called with", id);
    this.setState({ currentSelection: id });
  }

  toggle() {
    console.log(this.state);
    this.setState({
      isToggleOpen: !this.state.isToggleOpen
    });
  }

  buildMenu(items) {
    return (
      <ul>
        {items &&
          items.map(item => (
            <li key={item.id}>
              <div>
                {item.name}
                {item.children && item.children.length > 0
                  ? this.buildMenu(item.children)
                  : null}
              </div>
            </li>
          ))}
      </ul>
    );
  }

  render() {
    return (
      <div>
        <h2>Click any of the below option</h2>
        {this.state.menuItems &&
          this.state.menuItems.map((item, index) => {
            return (
              <div key={index}>
                {item.name}
                {this.buildMenu(item.children)}
              </div>
            );
          })}
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/reactstrap/4.8.0/reactstrap.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/reactstrap/4.8.0/reactstrap.min.css" />
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.development.js"></script>

【问题讨论】:

  • @TJCrowder,如果我没记错的话,这就是 react OP 将如何发布问题并提供指向代码沙箱的链接,这是我在 Stack Overflow 中看到的最大内容。即使是有角度的,他们也提供Stackblitz 链接.. 甚至人们只在此类链接中要求最小可复制链接。主要是反应。
  • 我不确定谁投了反对票,尽管我的问题很清楚并且我已经尝试了最大的尝试..
  • 在哪里你需要得到id?我看不出你打算在哪里使用它。
  • @TJCrowder,我无法找到在代码 sn-p 中创建两个不同文件的方法,例如 index.jsservice.js,因为它一次只允许一个文件.. 可能我得到你的帮助来做这件事..
  • @TJCrowder,我已经对我真正需要的东西做了一个简单的sn-p。所以你现在能帮我吗..在我需要分配的最后一个级别之前以相应 id 作为值的复选框..

标签: javascript reactjs recursion react-redux reactstrap


【解决方案1】:
buildMenu(items) {
    return (
      <ul>
        {items &&
          items.map((item, index) => (
            <li key={item.id}>
              <div>
                {this.state.isToggleOpen}
                {(item.children) ?  'Not Last': 'Here you can apply your check box'} //this check if item have children 
                <Button onClick={this.toggle.bind(this)}> {item.name} {index} </Button>

                <Collapse isOpen={this.state.isToggleOpen}>
                  {item.children && item.children.length > 0
                    ? this.buildMenu(item.children, index)
                    : null}
                </Collapse>
              </div>
            </li>
          ))}
      </ul>
    );
  }

现在渲染的第二种情况

<Button onClick={this.toggle.bind(this)}> {item.name}</Button>

检查项目是否有孩子

{(item.children) ? this.buildMenu(item.children) : 'Apply your checkbox here'}

完整代码

import React from "react";
import { render } from "react-dom";
import { loadMenu } from "./service";
import { Button, Collapse } from "reactstrap";

// const buildMenu = function buildMenu(items)

// const Menu = ({ items }) => buildMenu(items);

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      currentSelection: "",
      menuItems: [],
      isToggleOpen: false
    };
  }

  componentDidMount() {
    loadMenu().then(items => this.setState({ menuItems: items }));
  }

  handleClick(id, evt) {
    evt.preventDefault();
    console.log("click handler called with", id);
    this.setState({ currentSelection: id });
  }

  toggle() {
    console.log(this.state);
    this.setState({
      isToggleOpen: !this.state.isToggleOpen
    });
  }

  buildMenu(items) {
    return (
      <ul>
        {items &&
          items.map(item => (
            <li key={item.id}>
              <div>
                {this.state.isToggleOpen}
                {(item.children) ?  'Not Last': 'Here you can apply your check box'}
                <Button onClick={this.toggle.bind(this)}> {item.name} </Button>
                <Collapse isOpen={this.state.isToggleOpen}>
                  {item.children && item.children.length > 0
                    ? this.buildMenu(item.children)
                    : null}
                </Collapse>
              </div>
            </li>
          ))}
      </ul>
    );
  }

  render() {
    console.log(this.state.menuItems);
    return (
      <div>
        <h2>Click any of the below option</h2>
        {this.state.menuItems &&
          this.state.menuItems.map((item, index) => {
            return (
              <div>
                <Button onClick={this.toggle.bind(this)}> {item.name} </Button>
                {(item.children) ?  'Not Last': 'Here you can apply your check box'}
                <Collapse isOpen={this.state.isToggleOpen}>
                  {this.buildMenu(item.children)}
                </Collapse>
              </div>
            );
          })}
      </div>
    );
  }
}

render(<App />, document.getElementById("root"));

【讨论】:

  • 让我知道将我的答案投票为 {(item.children) 的原因? 'Not Last': 'Here you can apply your check box'} 将检查项目是否还有其他子项,如果没有,则用户可以应用复选框。只是无缘无故地投票不是一种方法。如果有任何问题,我将不胜感激。谁投了反对票。
  • @TestUser 我没有添加复选框,但您可以使用代码获取最后一个元素。只需将您的 buildMenu 方法替换为上面的方法即可。并添加 {(item.children) ? this.buildMenu(item.children) : 'Apply your checkbox here'} 在渲染中使用的
  • 它不适用于第一级,例如,foursix..
  • 我需要为最后一项分配复选框,就像我在左侧给出的问题 [Checkbox with value as 1.1.1] One-One-One 复选框和右侧的相应文本,复选框值为 id 但是不幸的是,您的解决方案不能满足我的需要。无论如何,非常感谢您的帮助和时间..
猜你喜欢
  • 2019-05-08
  • 1970-01-01
  • 2020-08-18
  • 2020-10-27
  • 1970-01-01
  • 1970-01-01
  • 2015-03-01
  • 2013-04-21
相关资源
最近更新 更多