【问题标题】:React Hook select multiple items with iconsReact Hook 用图标选择多个项目
【发布时间】:2020-02-15 08:15:04
【问题描述】:

我正在尝试实现一个包含许多项目的弹出框,用户可以在其中多选它们。当用户单击一个项目时,右侧会显示一个字体很棒的图标。

用户可以选择多个项目,并且右侧会显示一个图标以表明它已被选中。单击时此图标会切换。我的问题是我的事件处理程序与所有项目相关联,每当我单击一个项目时,都会检查所有项目。

我是新来的钩子和反应。我还尝试在数组中分配所选项目的 Id。它不会追加。

const SettingsComponent = (props) => {
const urlStofTyper = stofTyperUrl; 
const stofTyper = [];
const [isPopoverOpen, setPopoverOpen] = useState(false);

const [isItemChecked, setItemChecked] = useState(false);

const [error, setError] = useState(null);
const [loading, setLoading] = useState(null);
const [stoftype, setStoftyper] = useState({ DataList: [] });

const toggle = () => setPopoverOpen(!isPopoverOpen);

const sectionClicked = (e) => {
setItemChecked(!isItemChecked);
let secId = e.target.parentNode.getAttribute("data-section");   
if (!isItemChecked) {
    stofTyper.push(secId);
   } else {
    stofTyper.filter((sec) => sec == secId);
  }
};

useEffect(() => {
fetchStoftyper({ setError, setLoading, setStoftyper });
}, []);

const fetchStoftyper = async ({ setError, setLoading, setStoftyper }) => {
try {
    setLoading(true);
    const response = await Axios(urlStofTyper);
    const allStofs = response.data;
    setLoading(false);
    setStoftyper(allStofs);
  } catch (error) {
    setLoading(false);
    setError(error);
  }
};

return (
<React.Fragment>
  <div className='list-header-icons__fontawesome-icon' id='PopoverClick'>
    <FontAwesomeIcon icon={faCog} />
  </div>
  <Popover
    isOpen={isPopoverOpen}
    placement='bottom'
    toggle={toggle}
    target='PopoverClick'>
    <PopoverHeader>formatter</PopoverHeader>
    <div className='popover-body'>
      <ul className='individual-col--my-dropdown-menu-settings'>
        {stoftype.DataList.map((item) => (
          <li key={item.Id} className='section-items'>
            <a
              onClick={sectionClicked}                 
              className='dropdown-item'                 

              data-section={item.Sections[0].SectionId}
              data-format={
                item.Formats.length > 0
                  ? item.Formats[0].FormatId
                  : ""
              }
              aria-selected='false'>
              <span className='formatter-name'>
                {item.Name}
              </span>
              {isItemChecked && (
                <span className='formatter-check-icon'>
                  <FontAwesomeIcon icon={faCheck} size='lg' />
                </span>
              )}
            </a>
          </li>
        ))}
      </ul>
    </div>
  </Popover>
</React.Fragment>
);

【问题讨论】:

    标签: reactjs react-hooks


    【解决方案1】:

    现在您正在使用一个布尔变量来检查是否应该显示图标,它不起作用,因为您的DataList 中的每个项目都应该有它自己的单独指示器。

    一种可能的解决方案是为此目的使用new Map(),并将item.id 存储为索引和true/false 作为值,因此您选择的状态将如下所示:

    Map(3) {1 => true, 2 => true, 3 => false}
    

    之后,您可以检查是否应按如下方式显示您的图标:

    !!selected.get(item.id) 
    

    如果 HashTable 中的值为 true,则返回 true,如果为 false 或根本不存在,则返回 false。这应该足以实现您要求的功能。

    对于真实示例,您可以查看flatlist-selectable section from official Facebook docs 他们展示了如何使用这种技术实现多选。希望对您有所帮助。

    【讨论】:

    • 您好 Nikolai,感谢您付出时间和精力。我会调查并回来的。
    【解决方案2】:

    最后,我为自己的问题找到了解决方案。即使,我不需要上述解决方案,但我认为尝试解决它是一个好习惯。 Popover 不相关,因为它仅用作包装器。下面的解决方案仍然可以放在 Popover 中。

    CodeSandBox 链接:Demo here 使用 Class 组件,我会尽快尝试使用 hooks 重写。

    此解决方案依赖于 Bootstrap 4 和 Fontawesome。

    import React, { Component } from "react";
    import Cars from "./DataSeed";
    
    class DropDownWithSelect extends Component {
      constructor(props) {
        super(props);
    
        this.toggleDropdown = this.toggleDropdown.bind(this);
    
        this.state = {
          isDropDownOpen: false,
          idsOfItemClicked: []
        };
      }
    
      toggleDropdown = evt => {
        this.setState({
          isDropDownOpen: !this.state.isDropDownOpen
        });
      };
    
      toggleItemClicked = id => {
        this.setState(state => {
          const idsOfItemClicked = state.idsOfItemClicked.includes(id)
            ? state.idsOfItemClicked.filter(x => x !== id)
            : [...state.idsOfItemClicked, id];
    
          return {
            idsOfItemClicked
          };
        });
      };
    
      render() {
        return (
          <div className="dropdown">
            <button
              onClick={this.toggleDropdown}
              className="btn btn-secondary dropdown-toggle"
              type="button"
              id="dropdownMenuButton"
              data-toggle="dropdown"
              aria-haspopup="true"
              aria-expanded="false"
            >
              Dropdown button
            </button>
            {this.state.isDropDownOpen && (
              <div
                className="dropdown-menu show"
                aria-labelledby="dropdownMenuButton"
              >
                {Cars.map(x => {
                  return (
                    <div
                      key={x.id}
                      onClick={() => this.toggleItemClicked(x.id)}
                      className="dropdown-item d-inline-flex justify-content-between"
                    >
                      <span className="d-flex"> {x.name} </span>
                      <span className="d-flex align-self-center">
                        {this.state.idsOfItemClicked.includes(x.id) && (
                          <i className="fa fa-times" aria-hidden="true" />
                        )}
                      </span>
                    </div>
                  );
                })}
              </div>
            )}
          </div>
        );
      }
    }
    export default DropDownWithSelect;
    

    数据,即 ./DataSeed

        const cars = [
      {
        id: 1,
        name: "BMW",
        cost: 450000
      },
      {
        id: 2,
        name: "Audi",
        cost: 430000
      },
      {
        id: 3,
        name: "Mercedes",
        cost: 430000
      }
    ];
    
    export default cars;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-08-21
      • 2019-12-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-08
      • 1970-01-01
      相关资源
      最近更新 更多