【问题标题】:Filtering and then selecting shows wrong output: ReactJS过滤然后选择显示错误的输出:ReactJS
【发布时间】:2020-07-20 13:58:02
【问题描述】:

我有一个嵌套的复选框树,我可以在其中根据搜索字段过滤掉项目。当我搜索它选择项目时,场景明智,但每当我删除搜索项目时,它都不会保留。我正在尝试搜索http,当我检查然后删除搜索文本时,检查的项目没有被保留

有人可以帮我吗?

https://codesandbox.io/s/react-checkbox-tree-add-new-child-3c0yt?file=/src/components/Widget.js:0-4239

import React from "react";
import CheckboxTree from "react-checkbox-tree";
import "react-checkbox-tree/lib/react-checkbox-tree.css";

const nodes = [
  {
    value: "/app",
    label: "app",
    children: [
      {
        value: "/app/Http",
        label: "Http",
        children: [
          {
            value: "/app/Http/Controllers",
            label: "Controllers",
            children: [
              {
                value: "/app/Http/Controllers/WelcomeController.js",
                label: "WelcomeController.js"
              }
            ]
          },
          {
            value: "/app/Http/routes.js",
            label: "routes.js"
          }
        ]
      },
      {
        value: "/app/Providers",
        label: "Providers",
        children: [
          {
            value: "/app/Http/Providers/EventServiceProvider.js",
            label: "EventServiceProvider.js"
          }
        ]
      }
    ]
  },
  {
    value: "/config",
    label: "config",
    children: [
      {
        value: "/config/app.js",
        label: "app.js"
      },
      {
        value: "/config/database.js",
        label: "database.js"
      }
    ]
  },
  {
    value: "/public",
    label: "public",
    children: [
      {
        value: "/public/assets/",
        label: "Welcome",
        children: [
          {
            value: "/public/assets/style.css",
            label: "style.css"
          }
        ]
      },
      {
        value: "/public/index.html",
        label: "index.html"
      }
    ]
  },
  {
    value: "/.env",
    label: ".env"
  },
  {
    value: "/.gitignore",
    label: ".gitignore"
  },
  {
    value: "/README.md",
    label: "README.md"
  }
];

class Widget extends React.Component {
  state = {
    checked: [],
    expanded: [],
    filterText: "",
    nodesFiltered: nodes,
    nodes
  };

  constructor(props) {
    super(props);
    this.onCheck = this.onCheck.bind(this);
    this.onExpand = this.onExpand.bind(this);
    this.onFilterChange = this.onFilterChange.bind(this);
    this.filterTree = this.filterTree.bind(this);
    this.filterNodes = this.filterNodes.bind(this);
  }

  onCheck(checked) {
    this.setState({ checked });
  }

  onExpand(expanded) {
    this.setState({ expanded });
  }

  onFilterChange (e) {
    this.setState({ filterText: e.target.value }, this.filterTree);
  }

  filterTree() {
    // Reset nodes back to unfiltered state
    if (!this.state.filterText) {
      this.setState(prevState => ({
        nodesFiltered: prevState.nodes
      }));
      return;
    }
    const nodesFiltered = prevState => ({
      nodesFiltered: prevState.nodes.reduce(this.filterNodes, [])
    });
    this.setState(nodesFiltered);
  }

  filterNodes(filtered, node) {
    const { filterText } = this.state;
    let children;
    if (!!node.children) {
      children = node.children.reduce(this.filterNodes, []);
    }
    if (node.label.toLocaleLowerCase().indexOf(filterText.toLocaleLowerCase()) > -1 | (children && children.length)
    ) 
   {
      var expanded = [];
      expanded = [node.value, ...this.getAllValuesFromNodes(children)];
      this.setState({ expanded });
      if (!!node.children) {
        filtered.push({ ...node, children });
      } else {
        filtered.push(node);
      }
    }
    return filtered;
  }

  getAllValuesFromNodes = (nodes, leafnode) => {
    const values = [];
    if (!!nodes)
      for (let n of nodes) {
        values.push(n.value);
        if (n.children) {
          values.push(...this.getAllValuesFromNodes(n.children, false));
        }
      }
    return values;
  };

  render() {
    const { checked, expanded, filterText, nodesFiltered } = this.state;
    return (
      <div className="filter-container">
        <input
          className="filter-text"
          placeholder="Search..."
          type="text"
          value={filterText}
          onChange={this.onFilterChange}
        />
        <CheckboxTree
          checked={checked}
          expanded={expanded}
          nodes={nodesFiltered}
          onCheck={this.onCheck}
          onExpand={this.onExpand}
        />
      </div>
    );
  }
}

export default Widget;

【问题讨论】:

    标签: javascript reactjs ecmascript-6 setstate


    【解决方案1】:

    您还需要检查所有孩子,即使他们没有落入过滤器。 所以我建议添加两个函数,第一个用于查找所有子值,第二个用于按值查找节点中的节点:

      getChildrenValue(item) {
        if (typeof item.children === "undefined") {
          return [item.value];
        }
        let values = [item.value];
        item.children.forEach(c => {
          values = [...values, this.getChildrenValue(c)];
        });
        return values.flat();
      }
    
      findNodeByValue(data, value) {
        for (var i = 0; i < data.length; i++) {
          if (data[i].value === value) {
            return data[i];
          } else if (typeof data[i].children !== "undefined") {
            const nodeInChild = this.findNodeByValue(data[i].children, value);
            if (nodeInChild) {
              return nodeInChild;
            }
          }
        }
        return;
      }
    

    然后你可以在onCheck函数中使用它:

      onCheck(checked, targetNode) {
        const checkedValues = { checked };
        const node = this.findNodeByValue(nodes, targetNode.value);
        const allNodes = this.getChildrenValue(node);
        if (!this.state.checked.includes(targetNode.value)) {
          checkedValues.checked = [...checkedValues.checked, allNodes].flat();
        } else {
          checkedValues.checked = checkedValues.checked.filter(
            c => !allNodes.includes(c)
          );
        }
        this.setState({ checked: checkedValues.checked });
      }
    

    在操场上查看完整示例:https://codesandbox.io/s/react-checkbox-tree-add-new-child-6xcej?file=/src/components/Widget.js

    【讨论】:

    • 没错,我在操场和评论中修复了。不客气!
    • 哦,我也修好了:)在操场上
    • 再次抱歉给您带来麻烦:) 似乎无法正常工作。 1)从Welcome中选择style.css,它也会检查它的父级(Welcome)。现在,如果您尝试搜索Welcome,它的显示未选中Welcome 2) 在搜索Welcome 时,它应该返回两个条目,它返回app,而不显示WelcomeController,它位于app 和@987654332 内部@ 里面是public
    • 请看操场codesandbox.io/s/react-checkbox-tree-add-new-child-6xcej?file=/…。我们还需要将父项添加到我们的检查列表中
    猜你喜欢
    • 1970-01-01
    • 2017-05-23
    • 2016-04-15
    • 2020-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-28
    • 2015-11-21
    相关资源
    最近更新 更多